Beim Lesen von https://en.uncyclopedia.co/wiki/Haskell (und beim Ignorieren aller "anstößigen" Dinge) bin ich auf den folgenden verschleierten Code gestoßen:
fix$(<$>)<$>(:)<*>((<$>((:[{- thor's mother -}])<$>))(=<<)<$>(*)<$>(*2))$1
Wenn ich diesen Code ausführe ghci
(nach dem Importieren Data.Function
und Control.Applicative
), wird ghci
die Liste aller Potenzen von 2 gedruckt.
Wie funktioniert dieser Code?
Antworten:
Zunächst haben wir die schöne Definition
Das ist an sich schon ein bisschen umwerfend, wenn Sie es noch nie gesehen haben. Auf jeden Fall ist es ein ziemlich normaler Trick der Faulheit und Rekursion. Jetzt werden wir die explizite Rekursion mit
fix
und point-free-ify los.Das nächste, was wir tun werden, ist den
:
Abschnitt zu erweitern und dasmap
unnötig komplex zu machen.Nun haben wir zwei Kopien dieser Konstante
1
. Das wird niemals funktionieren, also werden wir den Reader-Applikativ verwenden, um das zu duplizieren. Außerdem ist die Funktionszusammensetzung ein bisschen Unsinn. Ersetzen(<$>)
wir sie also durch wo immer wir können.Als nächstes: Dieser Aufruf von
map
ist viel zu lesbar. Aber es gibt nichts zu befürchten: Wir können die Monadengesetze verwenden, um sie ein wenig zu erweitern. Insbesonderefmap f x = x >>= return . f
alsoWir können punktfrei ify, ersetzen
(.)
mit(<$>)
, und fügen Sie dann einige falsche Abschnitte:Ersetzen Sie diese Gleichung in unserem vorherigen Schritt:
Schließlich brechen Sie Ihre Leertaste und erstellen die wunderbare endgültige Gleichung
quelle
{- thor's mother -}
!Schrieb eine lange Antwort mit einem vollständigen Durchlauf meiner IRC-Protokolle der Experimente, die zum endgültigen Code führten (dies war Anfang 2008), aber ich habe versehentlich den gesamten Text :) Allerdings kein so großer Verlust - für die Zum größten Teil ist Daniels Analyse genau richtig.
Folgendes habe ich begonnen:
Die Unterschiede sind hauptsächlich auf die Reihenfolge zurückzuführen, in der die Refactorings durchgeführt wurden.
x = 1 : map (2*) x
ich mit angefangen2 : map ...
und die ersten 2 bis zur letzten Version beibehalten, wo ich eine eingedrückt(*2)
und die$2
am Ende in geändert habe$1
. Der Schritt "Karte unnötig komplex machen" fand nicht statt (so früh).map
Funktion wurde aktiviert, bevor liftM2 durch anwendbare Kombinatoren ersetzt wurde. Dann verschwanden auch alle Räume..
für die Funktionskomposition übrig. Das Ersetzen all dieser durch<$>
anscheinend erfolgte einige Zeit in den Monaten zwischen dieser und der Unzyklopädie.Übrigens, hier ist eine aktualisierte Version, in der die Nummer nicht mehr erwähnt wird
2
:quelle
Beide Antworten leiten das verschleierte Code-Snippet aus dem aus heiterem Himmel gegebenen kurzen Original ab, aber die Frage fragt tatsächlich, wie der lange verschleierte Code seine Aufgabe erfüllt.
Hier ist wie:
Hier
( (\ x -> [2*x]) =<<) = (>>= (\ x -> [2*x])) = concatMap (\ x -> [2*x]) = map (2*)
ist eine Funktion, also noch einmal<$> = .
:sind alle Potenzen von 2 in aufsteigender Reihenfolge.
Dies verwendet
A <$> B <*> C $ x = liftA2 A B C x
und da es auf eine FunktionliftA2 A B C
angewendet wird, bedeutetx
es als FunktionliftA2 A B C x = A (B x) (C x)
.(f `op` g) = op f g = (f `op`) g = (`op` g) f
sind die drei Gesetze der Betreiberabschnitte>>=
ist monadisch binden, und da(`op` g) f = op f g
und die Typen sindDurch Typanwendung und Substitution sehen wir, dass die fragliche Monade
[]
für welche ist(>>= g) = concatMap g
.concatMap (\ x -> [2*x]) xs
wird vereinfacht alsund per Definition,
wo
damit
quelle