Da Sie dies mit Haskell markiert habe, werde ich in dieser Hinsicht zu beantworten: In Haskell, das entspricht einer CPS-Transformation zu tun, arbeitet in der Cont
Monade, der einen Wert x
in eine Funktion höherer Ordnung transformiert, dass nimmt ein Argument und wendet es auf x
an.
Also, mit zu beginnen, hier ist 1 + 2 in regelmäßiger Haskell: (1 + 2)
Und hier ist es in der Fortsetzung Monade:
contAdd x y = do x' <- x
y' <- y
return $ x' + y'
... nicht sehr informativ. Um zu sehen, was los ist, lass uns die Monade auseinander nehmen. Zunächst Entfernen der do
Notation:
contAdd x y = x >>= (\x' -> y >>= (\y' -> return $ x' + y'))
Die return
Funktion einen Wert in das monadisch hebt, und in diesem Fall wird als \x k -> k x
implementiert oder eine Infixoperator Abschnitt als \x -> ($ x)
verwenden.
contAdd x y = x >>= (\x' -> y >>= (\y' -> ($ x' + y')))
Der (>>=)
Operator (read "bind") -Ketten zusammen Berechnungen in dem monadisch, und in diesem Fall wird als \m f k -> m (\x -> f x k)
umgesetzt. Ändern die Bindefunktion prefix Form und in der Lambda-Substitution, sowie einige Umbenennungs zur Klarheit:
contAdd x y = (\m1 f1 k1 -> m1 (\a1 -> f1 a1 k1)) x (\x' -> (\m2 f2 k2 -> m2 (\a2 -> f2 a2 k2)) y (\y' -> ($ x' + y')))
einige Funktionsanwendungen Reduzierung:
contAdd x y = (\k1 -> x (\a1 -> (\x' -> (\k2 -> y (\a2 -> (\y' -> ($ x' + y')) a2 k2))) a1 k1))
contAdd x y = (\k1 -> x (\a1 -> y (\a2 -> ($ a1 + a2) k1)))
und ein wenig endgültigen Neuanordnung und Umbenennung:
contAdd x y = \k -> x (\x' -> y (\y' -> k $ x' + y'))
Mit anderen Worten: Die Argumente für die Funktion wurden von Zahlen in Funktionen geändert, die eine Zahl nehmen und das Endergebnis des gesamten Ausdrucks zurückgeben, jus t wie Sie es erwarten würden.
Bearbeiten: Ein Kommentator weist darauf hin, dass contAdd
selbst noch zwei Argumente im Curry-Stil dauert. Dies ist sinnvoll, da die Fortführung nicht direkt, sondern nicht notwendig ist. Um sonst zu tun, dann würden Sie müssen zunächst die Funktion auseinander zwischen den Argumenten brechen:
contAdd x = x >>= (\x' -> return (\y -> y >>= (\y' -> return $ x' + y')))
Und dann ist es wie folgt verwenden:
foo = do f <- contAdd (return 1)
r <- f (return 2)
return r
Hinweis, dass dies wirklich nicht anders aus der früheren Version ; es packt einfach das Ergebnis jeder Teilanwendung als eine Fortsetzung, nicht nur das Endergebnis. Da Funktionen erstklassige Werte sind, gibt es keinen signifikanten Unterschied zwischen einem CPS-Ausdruck, der eine Zahl enthält, und einem, der eine Funktion hält.
Denken Sie daran, dass ich hier Dinge auf sehr ausführliche Art und Weise schreibe, um alle Schritte explizit zu machen, wo etwas im Fortsetzungsstil ist.
Nachtrag: Sie können feststellen, dass der endgültige Ausdruck der de-gezuckerten Version des monadischen Ausdruck sehr ähnlich sieht. Dies ist kein Zufall, da die einwärts verschachtelnde Natur der monadischen Ausdrücke, die es ihnen erlauben, die Struktur der Berechnung basierend auf vorherigen Werten zu ändern, eng mit dem Fortsetzungs-Passing-Stil verbunden ist; In beiden Fällen haben Sie in gewisser Weise einen Kausalitätsbegriff verdinglicht.
Vielleicht bin ich die einzige Person, die nicht wusste, was CPS in diesem Zusammenhang bedeutet. :-) Oder vielleicht nicht. Wenn nicht: http://en.wikipedia.org/wiki/Continuation-passing_style –
Beachten Sie, dass CPS in zwei Formen kommt: Es ist entweder ein Paradigma (z. B. Cont) oder ein Implementierungsdetail (z. B. Codensity). Im ersten Fall verwandelt es natürlich jede Funktion in eine Funktionsfunktion, d. H. Es fügt ein weiteres Argument hinzu. In letzterem ist es nur, wie es unter der Haube umgesetzt wird. Einige Sprachen verwenden überall CPS, während sie eine Nicht-CPS-Schnittstelle bereitstellen, wobei Scheme das kanonische Beispiel ist. Aber dann gehen die meisten Scheme-Implementierungen weiter und stellen diese Implementierungsdetails als Sprachfunktion namens call/cc zur Verfügung. – ertes