Ao ler https://en.uncyclopedia.co/wiki/Haskell (e ignorando todas as coisas "ofensivas"), me deparei com a seguinte parte do código ofuscado:
fix$(<$>)<$>(:)<*>((<$>((:[{- thor's mother -}])<$>))(=<<)<$>(*)<$>(*2))$1
Quando executo esse trecho de código em ghci
(após importar Data.Function
e Control.Applicative
), ghci
imprime a lista de todas as potências de 2.
Como funciona esse código?
Respostas:
Para começar, temos a bela definição
o que por si só é um pouco alucinante, se você nunca viu antes. De qualquer forma, é um truque bastante comum de preguiça e recursão. Agora, vamos nos livrar da recursão explícita usando
fix
e point-free-ify.A próxima coisa que vamos fazer é expandir a
:
seção e tornar omap
desnecessariamente complexo.Bem, agora temos duas cópias dessa constante
1
. Isso nunca vai funcionar, então usaremos o aplicativo do leitor para eliminar a duplicação. Além disso, a composição de funções é um pouco lixo, então vamos substituí-la(<$>)
sempre que pudermos.A seguir: essa chamada para
map
é muito legível. Mas não há nada a temer: podemos usar as leis da mônada para expandi-lo um pouco. Em particularfmap f x = x >>= return . f
, entãoPodemos apontar livremente, substituir
(.)
por(<$>)
e, em seguida, adicionar algumas seções espúrias:Substituindo esta equação em nossa etapa anterior:
Finalmente, você quebra a barra de espaço e produz a maravilhosa equação final
fonte
{- thor's mother -}
!Estava escrevendo uma longa resposta com uma análise completa dos meus logs de IRC dos experimentos que levaram ao código final (isso foi no início de 2008), mas eu acidentalmente todo o texto :) Não é uma grande perda - para o a maior parte da análise de Daniel está correta.
Aqui está o que eu comecei:
As diferenças se resumem principalmente à ordem em que as refatorações aconteceram.
x = 1 : map (2*) x
eu comecei com2 : map ...
, e mantive aquele 2 inicial até a última versão, onde apertei um(*2)
e mudei o$2
no final para$1
. A etapa "tornar o mapa desnecessariamente complexo" não aconteceu (tão cedo).map
função ofuscada foi colocada antes de substituir liftM2 por combinadores Aplicativos. Foi então que todos os espaços desapareceram..
para composição de funções sobrando. A substituição de todos por<$>
aparentemente aconteceu algum tempo nos meses entre isso e a desciclopédia.BTW, aqui está uma versão atualizada que não menciona mais o número
2
:fonte
Ambas as respostas derivam o trecho de código ofuscado do original curto fornecido do nada, mas a questão realmente pergunta como o código ofuscado faz seu trabalho.
Veja como:
Aqui
( (\ x -> [2*x]) =<<) = (>>= (\ x -> [2*x])) = concatMap (\ x -> [2*x]) = map (2*)
está uma função, então, novamente<$> = .
:são todas as potências de 2 , em ordem crescente.
Isso usa
A <$> B <*> C $ x = liftA2 A B C x
e, uma vez queliftA2 A B C
é aplicado ax
uma função, significa uma funçãoliftA2 A B C x = A (B x) (C x)
.(f `op` g) = op f g = (f `op`) g = (`op` g) f
são as três leis das seções de operação>>=
é ligação monádica, e desde que(`op` g) f = op f g
e os tipos sãopela aplicação e substituição de tipo, vemos que a mônada em questão é
[]
para qual(>>= g) = concatMap g
.concatMap (\ x -> [2*x]) xs
é simplificado comoe por definição,
Onde
de modo a
fonte