Was ist mit call/cc?
Ich habe mehrmals versucht, um zu begreifen, das Konzept der Fortsetzungen und call/cc. Jeder einzelne Versuch war ein Fehlschlag. Kann jemand bitte erklären Sie mir, diese Konzepte, idealerweise mit realistischer Beispiele als diese, auf Wikipedia oder in anderen SO posten.
Habe ich den hintergrund in der web-Programmierung und OOP. Ich verstehe auch 6502 assembly und hatte einen kleinen randez-vous mit Erlang. Aber immer noch, ich kann nicht umbrochen, mein Kopf herum call/cc.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Schauen, ich habe festgestellt, das Continuation-Passing-Style beste Beschreibung zu diesem Thema.
Hier beraubt details Kopie von diesem Artikel:
Vergleich zu C, die aktuelle Fortsetzung ist wie der aktuelle Zustand des Stacks. Es hat alle Funktionen, die warten auf das Ergebnis der aktuellen Funktion zu beenden, so dass Sie können die Ausführung fortsetzen. Die variable erfasst die aktuelle Fortsetzung ist wie eine Funktion, mit der Ausnahme, dass der bereitgestellte Wert und gibt es zurück zu den wartenden Stapel. Dieses Verhalten ist ähnlich der C-Funktion longjmp, wo Sie zurückkehren können, um die unteren Teile des Stapels sofort.
Einen entscheidenden Unterschied zwischen den C-stack und eine Fortsetzung ist, dass eine Fortsetzung kann an jeder beliebigen Stelle im Programm, auch wenn der Zustand des Stacks verändert hat. Dies bedeutet, dass Sie im wesentlichen die Wiederherstellung von früheren Versionen von stack und verwenden Sie wieder und wieder, was zu einigen einzigartigen Programm fließen.
Die Möglichkeit zum speichern und wiederherstellen den Zustand, der ein Programm hat viel mit multithreading. In der Tat, können Sie die Implementierung eigener thread-scheduler mit Fortsetzungen, wie ich versucht habe zu verdeutlichen hier.
Ein triviales Beispiel für die Verwendung der Fortsetzung wäre die Implementierung einer thread - (Faser, wenn Sie es wünschen) - manager auf einem ein-Prozessor-Maschine. Der scheduler würde die Unterbrechung der Ausführung fließen in regelmäßigen Abständen (oder in dem Fall von Fasern, die aufgerufen werden, die an verschiedenen strategischen Punkten im code), speichern Sie die Fortsetzung state (entsprechend der aktuellen thread), dann wechseln Sie zu einem anderen Fortsetzung state (entsprechend einem anderen thread, dessen Zustand war vorher gespeichert haben.)
Unter Bezugnahme auf Ihre assembly hintergrund, die Fortführung Zustand erfassen würde details wie Befehlszähler, Register und stack-Kontext (Zeiger), werden gespeichert und wiederhergestellt werden.
Einen anderen Weg, mit Fortsetzung wäre denken zu ersetzen Methodenaufrufe mit mehreren thread-wie Entitäten, die co-existieren parallel (entweder ausgeführt oder angehalten), die Kontrolle über Fortsetzung Kontexten statt der 'klassischen'
call
Paradigma. Sie operieren würde auf Globale (shared) Daten, anstatt sich auf Parameter. Dies ist zum Teil flexibler alscall
in dem Sinne, dass der Stapel nicht zu wind-up, dann nach unten (calls
sind verschachtelte), aber die Kontrolle übergeben können, um willkürlich.Versucht zu visualisieren das Konzept in einer Sprache, die wie ein C, man Stelle sich vor, eine große Schleife mit einem einzigen
switch(continuation_point) { case point1: ... }
- Anweisung, wobei jedescase
entspricht einer Fortsetzung-savepoint, und wo der code innerhalb jedescase
können, ändern Sie den Wert fürcontinuation_point
und der Verzicht auf die Kontrolle zu, dasscontinuation_point
durchbreak
ing von derswitch
und die Gewinnung der nächsten iteration in der Schleife.Was ist der Zusammenhang mit deiner Frage? Jeder bestimmte Szenarien, die Sie interessiert sind? Irgendeine bestimmte Programmiersprache? Ist der Faden/Faser-Beispiel oben ausreichend?
Die Sache, die mir geholfen haben, das ist die Idee, dass in einer traditionellen Sprache mit Funktion fordert Sie implizit übergeben Sie die Fortsetzung jedes mal, wenn Sie eine Funktion aufrufen.
Vor dem Sprung zu einer Funktion des code-Sie sparen Zustand auf dem stack (d.h. schieben Sie Ihre return-Adresse und der stack enthält bereits Ihrem einheimischen). Dies ist im wesentlichen eine Fortsetzung. Wenn die Funktion abgeschlossen hat, die es zu bestimmen hat, wo senden Sie den Ablauf der Ausführung. Es verwendet die Fortsetzung auf dem stack gespeichert werden, knallen die Rückkehr-Adresse und springen.
Andere Sprachen verallgemeinern diese Idee von Fortsetzungen, so dass Sie explizit angeben, wo weiterhin die Ausführung von code, anstatt implizit weiter, von wo aus die Funktion aufgerufen wurde.
BEARBEITEN, basierend auf Kommentar:
Die Fortsetzung ist der komplette ausführungszustand. An jedem Punkt der Ausführung, die Sie können, gliedert sich das Programm in zwei teilen (in Zeit, nicht Raum) - das, was ausgeführt wurde, zu diesem Punkt, und alles, was Los zu laufen von hier aus. Die "current continuation" ist "alles, was zum ausführen von hier" (man kann es wie eine Art von Funktion, die alles tun wird der rest des Programms getan haben). Also die Funktion, die Sie liefern, zu
call/cc
übergeben bekommt die Fortsetzung, die aktuell war, alscall/cc
aufgerufen wurde. Sie können die Funktion verwenden, die Fortsetzung zu return die Ausführung dercall/cc
Aussage (eher aber es wird passieren die Fortsetzung um etwas anderes, denn wenn es verwendet es direkt, könnte es nicht eine einfache Rückkehr statt).Wenn ich versuche zu verstehen, call/cc, fand ich diese call-with-current-continuation-für-C-Programmierer Seite war hilfreich.
Die beste Erklärung, die ich gesehen habe, ist in Paul Grahams Buch, Auf Lisp.
Stellen Sie sich Ihr Skript ist ein video-Spiel-Bühne. Call/cc ist wie eine bonus-Bühne.
Sobald Sie es berühren, werden Sie übertragen auf die bonus-stage (d.h. die definition der Funktion als argument übergeben, um Sie call/cc [f in diesem Fall]).
Bonus-stages unterscheiden sich von herkömmlichen Stadien, denn Sie haben in der Regel ein element (D. H. das argument der Funktion übergeben call/cc), dass, wenn Sie es berühren, verlieren Sie transportiert werden und zurück auf die normale Stufe.
Also ist es egal, wenn es viele
args
bei erreichen einer von Ihnen seine über. Damit unsere Ausführung erreicht(arg 42)
und gibt Sie an die Summe(+ 42 10)
.Da gibt es auch einige Ausführungen bemerkenswert:
Fortsetzung (das ist eine Funktion), können Sie ein f wie dieses:
(define f (lambda (k) (+ k 42))
, weil Sie nichtsum
eineFunktion.
(define f (lambda (k) (f 42 10)))
da die Fortsetzung erwartet nur ein argument.
ohne
touching
jeder Ausgang, in diesem Fall die Funktion Erlös wiejeder normale Funktion (z.B.
(define f (lambda (k) 42)
beendet undgibt 42).
(call-with-values (lambda () (call/cc (lambda (cont) (cont 1 2)))) (lambda (a b) (list a b))) ; ==> (1 2)
die Fortsetzung erwartet zwei Argumente.Es gibt mehrere Ebenen, um das Verständnis call/cc.
Zuerst müssen Sie die Begriffe verstehen und die, wie der Mechanismus funktioniert.
Dann ein Verständnis dafür, wie und Wann call/cc ist in "real life"
Programmierung erforderlich ist.
Der ersten Stufe kann erreicht werden durch das Studium CPS, aber es gibt
alternativen.
Der zweiten Stufe empfehle ich die folgenden klassischen Friedman.
Daniel P. Friedman.
"Anwendungen der Fortsetzungen: Eingeladen Tutorial".
1988 Prinzipien von Programmiersprachen (POPL88).
Januar 1988.
Werfen Sie einen Blick auf die Beschreibung und Implementierung von call/cc für FScheme: http://blogs.msdn.com/b/ashleyf/archive/2010/02/11/turning-your-brain-inside-out-with-continuations.aspx
Das Modell, das ich verwendet, die für das Verständnis Fortsetzungen von einem imperativen Sicht ist, dass es eine Kopie des call-stack in Kombination mit der ein Zeiger auf die nächste Anweisung.
Call/cc ruft eine Funktion (als argument übergeben), mit der Fortsetzung als argument.