Thread Gültigkeit von Variablen... oder so etwas.
(30 answers)
Opened by theresa at 2008-02-18 13:44
Goto mit Parametern gibt's in Perl auch:
Code (perl): (dl
)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 use 5.010; use strict; use warnings; sub foo { say 'Tail-calling bar...'; @_ = (1, 2); goto &bar; say 'This should never be reached!'; } sub bar { my ($a, $b) = @_; say "bar($a, $b) called"; } say 'Calling foo...'; foo(); say '... returned from foo'; Bei dieser Form von goto wird der aktuelle Funktionsaufruf durch einen neuen ersetzt, ohne dass ein neuer Stackframe angelegt wird. So etwas nennt man auch einen Tail-Call. Tail-Calls haben mit Continuation-passing-style nur insofern etwas zu tun, als letzterer ohne Tail-Calls zwangsläufig irgendwann zum Stapelüberlauf führt. Der eigentliche Sinn von Continuation-passing-style ist der, in einer Sprache, die das nicht nativ unterstützt, Continuations explizit zu machen, wobei eine Continuation so etwas wie der eingefrorene Zustand eines Programmes ist, das darauf wartet einen Rückgabewert zu empfangen und weiterzurechnen. Man ersetzt also jede Rückgabe eines Wertes durch den Aufruf einer Funktion, die als Parameter übergeben wurde. Normaler Code: Code (perl): (dl
)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 use 5.010; use strict; use warnings; sub square($) { my $x = shift; return $x * $x; } sub square_and_say($) { my $x = shift; my $s = square($x); say "$x ^ 2 = $s"; } square_and_say 2; Continuation-passing-style: Code (perl): (dl
)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 use 5.010; use strict; use warnings; sub square(&$) { my ($rc, $x) = @_; @_ = ($x * $x); goto &$rc; } sub square_and_say(&$) { my ($rc, $x) = @_; my $square_rc = sub { my $s = shift; say "$x ^ 2 = $s"; @_ = (); goto &$rc; }; @_ = ($square_rc, $x); goto □ } square_and_say { } 2; Diesen zusätzlichen Parameter für jede Funktion nennt man jetzt einfach die Rückgabe-Continuation der Funktion. Das ganze sieht umständlich aus und ist es auch, aber andererseits erkennt man, dass diese Transformation sehr kanonisch ist und leicht von einem Compiler automatisch durchgeführt werden könnte. Außerdem stellt man schnell fest, dass man sich hier neue Möglichkeiten der Programmierung eröffnet hat: Um in Perl-Terminologie zu sprechen, hat man nun praktisch in jeder Subroutinene eine Referenz \&return zur Verfügung nämlich die Return-Continuation der Subroutinen. Diese Referenz kann man nun aber nicht wie return nur in der Subroutine benutzen, zu der sie eigentlich gehört, sondern sie lustig in der Gegend herumübergeben und von anderen Stellen des Programmes aus aufrufen um den Kontrollfluss zu verändern. Auf Basis von Continuations kann man zum Beispiel trivial Exceptions mit optionalem Neustart des fehlerbehafteten Codes implementieren, oder Webapplikationen, die mehrere Formulare hintereinander präsentieren müssen schreiben, als handele es sich um ein lineares Programm, das nacheinander mehrere Seiten an den Browser sendet und die Eingaben einliest. Einfacher zu benutzen sind Continuations natürlich, wenn die Programmiersprache spezifische Unterstützung dafür mitbringt zum Beispiel indem der Compiler automatisch alles in Continuation-passing-style transformiert. Bekanntere Sprachen, die das können, sind zum Beispiel Scheme, JavaScript (in manchen neueren Versionen), Ruby, Smalltalk (manche Dialekte) und SML/NJ. Wie auch bei goto sollte man mit der exzessiven Verwendung von Continuations in der Regel vorsichtig sein, weil sonst niemand mehr das Programm versteht. Alles in allem sind sie aber eine nette Spielerei, die durchaus auch nützlich sein kann ;-) When C++ is your hammer, every problem looks like your thumb.
|