in reply to Re^7: Continuations in Perl - Returning to an arbitrary level up the call stack
in thread Continuations in Perl - Returning to an arbitrary level up the call stack

Already demonstrated:
No, this example is not about recursion (although there is some).
Nope! Jump-labels only change each time with_return constructs are called to avoid confusion if they are dynamically nested.
That's what I told - they change each time you _call_ with_return, not each time you have with_return in code.

Here is example. Try do same with "goto"

use strict; use warnings; use Return::MultiLevel qw/with_return/; sub rec { my ($i, $return) = (@_, undef); $i++; print "i=$i\n"; if ($i == 3) { with_return { my $newreturn = shift; rec($i, $newreturn); }; } if ($i == 5) { $return->() if $return; } if ($i == 7) { return; } rec($i, $return); } rec(0); __END__ $ perl ml.pl i=1 i=2 i=3 i=4 i=5 i=4 i=5 i=6 i=7
  • Comment on Re^8: Continuations in Perl - Returning to an arbitrary level up the call stack
  • Download Code

Replies are listed 'Best First'.
Re^9: Continuations in Perl - Returning to an arbitrary level up the call stack
by LanX (Saint) on May 19, 2013 at 01:51 UTC
    > Here is example.

    Well this is far beyond what the OP wanted!

    And your $return->() if $return clause makes it quite esoteric ...

    > Try do same with "goto"

    ... FWIW!

    use strict; use warnings; our $target=""; sub rec { my ($i) = @_; $i++; print "i=$i $target\n"; if ($i == 3) { target($i); } if ($i == 5) { goto $target if $target; } if ($i == 7) { return; } rec($i); } sub target { local $target="TARGET"; rec(shift); TARGET: } rec(0); __END__ i=1 i=2 i=3 i=4 TARGET i=5 TARGET i=4 i=5 i=6 i=7

    As I said it's only an abstraction of the goto mechanism!

    Good night! =)

    Cheers Rolf

    ( addicted to the Perl Programming Language)

      Well this is far beyond what the OP wanted!
      Why do you think so? he mention call stack:
      but to a higher point up the call stack.
      Your code is a bit cheat - you implemented another subroutine, just to remember point in the stack. In my code, during executiom, there was just one "longjump" always to same point, so you had to implement just one subroutine with one label. But in general case you need N goto lables (N is unknown at compilation stage), so it's impossible without eval EXPR (not eval BLOCK)
      Try this,
      use strict; use warnings; use Return::MultiLevel qw/with_return/; our %returns; sub rec { my ($i) = @_; $i++; print ">> i=$i\n"; if ($i <= 9) { with_return { $returns{$i} = shift; rec($i); }; } if (@ARGV) { my $r = shift @ARGV; print "RESTORE $r\n"; $returns{$r}->(); } print "<< i=$i\n"; } rec(0); __END__
      $perl ml_a.pl 6 >> i=2 >> i=3 >> i=4 >> i=5 >> i=6 >> i=7 >> i=8 >> i=9 >> i=10 RESTORE 6 << i=6 << i=5 << i=4 << i=3 << i=2 << i=1
      $perl ml_a.pl 3 >> i=1 >> i=2 >> i=3 >> i=4 >> i=5 >> i=6 >> i=7 >> i=8 >> i=9 >> i=10 RESTORE 3 << i=3 << i=2 << i=1

      And let's consider @ARGV as external input, which is available only just before program go to 'RESTORE' point, but not before program started a recursion

        This is getting more and more abstract and convoluted! Dynamic jump-levels? Come on...

        I'm hacking for 30 years now and never needed this! :)

        In this concrete case I would only call target() if a recursion level is really expected to be a jump target, that are 6 and 3 in your examples.

        (If not possible in advance I would just step back single levels (return or goto) till I reach the desired one, Something like eval "LABEL:" would be my very last resort)

        And even multiple calls to target are no problem, cause the goto always jumps to the last TARGET -label in the call-stack and local $target cares about restoring previous levels. This works w/o any string- eval.

        I would never use with_return in the way you are showing, because

        1. it's not obvious what it does, I can name the target() function in a expressive way

        2. it has plenty of overhead, many of my recursions are long-running branch-and-bound searches which need to be optimized.

        3. the need to explicitly pass the return-sub along is IMHO very annoying

        > Your code is a bit cheat - you implemented another subroutine, just to remember point in the stack.

        Nope, it's like in the original code I gave. And as I said Return::MultiLevel just uses the same technique under the hood.

        Anyway let's stop it here please! =)

        Cheers Rolf

        ( addicted to the Perl Programming Language)