Thread Currying in Schleifen
(18 answers)
Opened by flowdy at 2012-11-06 22:47 2012-11-06T21:47:48 flowdy Nun ja, das ganze Problem klingt prädestiniert für die Verwendung von Continuations, die es in Perl aber nicht gibt. Man könnte zur Holzhammermethode greifen und mit goto &SUB und CPS-Transformation arbeiten, ich bezweifle allerdings, dass das besonders hübsch ist. Die CPS-transformierte Schleife sähe ungefähr so aus:
Code (perl): (dl
)
1 2 3 4 5 6 7 8 9 10 11 12 sub Node::climb_up { my ($self, $proc) = @_; my $impl = __SUB__; @_ = ($self, sub { if ($self = $self->parent_row) { @_ = ($self, $proc); goto &$impl; } }); goto &$proc; } Und ein Aufruf der Methode in etwa so: Code (perl): (dl
)
1 2 3 4 5 6 7 8 9 10 $node->climb_up(sub { my ($node, $cont) = @_; if (should_continue($node)) { goto &$cont; } else { return 42; } }); Oder man könnte in diesem Fall Continuations über Exceptions emulieren, wobei man das sauber kapseln kann, so dass der Aufrufer von climb_up nichts davon sieht. In diesem Fall sähe die Schleife ungefähr so aus: Code (perl): (dl
)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 sub Node::climb_up { my ($self, $proc) = @_; my ($magic, @return); my $return = sub { @return = @_; die \$magic; }; while ($self) { eval { @return = $proc->($self, $return); $self = $self->parent_row; }; if ($@) { last if ($@ eq \$magic); die $@; } } return @return; } Und ein Aufruf der Method zum Beispiel so: Code (perl): (dl
)
1 2 3 4 5 6 7 8 9 10 $node->climb_up(sub { my ($node, $return) = @_; if (should_continue($node)) { return; } else { $return->(42); } }); An der Variante, eine Referenz auf ein Stopflag an das Callback zu übergeben finde ich auch nicht unbedingt etwas auszusetzen, wenngleich es mir wesentlich einfacher erscheint schlicht mehrere Rückgabewerte aus dem Callback zu verwenden. Zum Beispiel könnte das so aussehen: Code (perl): (dl
)
1 2 3 4 5 6 7 8 9 10 sub Node::climb_up { my ($self, $proc) = @_; my ($stop, @results); while ($self && !$stop) { ($stop, @results) = $proc->($self); $self = $self->parent_row; } return @results; } Und ein Aufruf der Method zum Beispiel so: Code (perl): (dl
)
1 2 3 4 5 6 7 8 9 10 $node->climb_up(sub { my ($node) = @_; if (should_continue($node)) { return 0; } else { return 1, 42; } }); When C++ is your hammer, every problem looks like your thumb.
|