Mientras leía https://en.uncyclopedia.co/wiki/Haskell (e ignorando todas las cosas "ofensivas"), me encontré con el siguiente código ofuscado:
fix$(<$>)<$>(:)<*>((<$>((:[{- thor's mother -}])<$>))(=<<)<$>(*)<$>(*2))$1
Cuando ejecuto ese fragmento de código ghci
(después de importar Data.Function
y Control.Applicative
), ghci
imprime la lista de todas las potencias de 2.
¿Cómo funciona este código?
Respuestas:
Para empezar, tenemos la hermosa definición
que en sí mismo es un poco alucinante si nunca lo has visto antes. De todos modos, es un truco bastante estándar de pereza y recursividad. Ahora, nos desharemos de la recursividad explícita usando
fix
, y point-free-ify.Lo siguiente que vamos a hacer es expandir la
:
sección y hacermap
innecesariamente complejo.Bueno, ahora tenemos dos copias de esa constante
1
. Eso nunca funcionará, así que usaremos el aplicativo del lector para eliminarlo. Además, la composición de funciones es un poco basura, así que reemplacemos eso con(<$>)
lo que podamos.A continuación: esa llamada a
map
es demasiado legible. Pero no hay nada que temer: podemos usar las leyes de las mónadas para expandirlo un poco. En particularfmap f x = x >>= return . f
, entoncesPodemos señalar, sin ify, sustituir
(.)
con(<$>)
, y luego añadir algunas secciones espurias:Sustituyendo esta ecuación en nuestro paso anterior:
Finalmente, rompes tu barra espaciadora y produces la maravillosa ecuación final
fuente
{- thor's mother -}
!Estaba escribiendo una respuesta larga con un repaso completo de mis registros de IRC de los experimentos que condujeron al código final (esto fue a principios de 2008), pero accidentalmente todo el texto :) Sin embargo, no es una gran pérdida, para el la mayor parte del análisis de Daniel es acertado.
Esto es lo que empecé con:
Las diferencias se reducen principalmente al orden en el que ocurrieron las refactorizaciones.
x = 1 : map (2*) x
comenzar con2 : map ...
, mantuve ese 2 inicial hasta la última versión, donde apreté a(*2)
y cambié el$2
al final por$1
. El paso de "hacer el mapa innecesariamente complejo" no sucedió (tan pronto).map
función ofuscada se instaló antes de reemplazar liftM2 con combinadores aplicativos. Ahí fue también cuando todos los espacios desaparecieron..
composición de funciones. Reemplazar todos aquellos con<$>
aparentemente sucedió en algún momento en los meses entre eso y la inciclopedia.Por cierto, aquí hay una versión actualizada que ya no menciona el número
2
:fuente
Ambas respuestas derivan el fragmento de código ofuscado del original corto dado de la nada, pero la pregunta en realidad pregunta cómo hace su trabajo el código largo y ofuscado.
Así es cómo:
Aquí
( (\ x -> [2*x]) =<<) = (>>= (\ x -> [2*x])) = concatMap (\ x -> [2*x]) = map (2*)
hay una función, así que de nuevo<$> = .
:son todas las potencias de 2 , en orden creciente.
Esto usa
A <$> B <*> C $ x = liftA2 A B C x
y dado queliftA2 A B C
se aplica ax
su función, significa una funciónliftA2 A B C x = A (B x) (C x)
.(f `op` g) = op f g = (f `op`) g = (`op` g) f
son las tres leyes de las secciones del operador>>=
es unión monádica, y dado que(`op` g) f = op f g
y los tipos sonpor tipo de aplicación y sustitución vemos que la mónada en cuestión es
[]
para cuál(>>= g) = concatMap g
.concatMap (\ x -> [2*x]) xs
se simplifica comoy por definición,
dónde
así que eso
fuente