in reply to Re: Perl6 lazy list of code blocks
in thread Perl6 lazy list of code blocks

Thank you, moritz, for your explanation, and in the process, for introducing me to several aspects of Perl6 I was unfamiliar with.

I am indeed seeking to build an indefinite list of closures, each one having an incremented value of $n. If this seems an odd request, then rest assured it's only because I've rendered this as an isolated, simplified problem for posting here; the more complex application uses an analogous data structure in an elemental way.

Your first suggestion...

my @blocks := (0..*).map: -> $n { -> $x, $y { $x * $y * $n } };

...seems just right, but it hangs rakudo-star-2012.04.

Your second suggestion...

sub gen($x, $y) { state $n = 0; $x*$y*$n++ } my @foo := &gen xx *;

...is, as you suggested, not what I'm looking for, because I want $n to reflect the ordinal position in the series, not the ordinal call order of the closure.

Your third suggestion...

my @foo := sub ($x, $y) { state $n = 0; $x*$y*$n++ } xx *;

...gives every element of @foo the same ordinal position in the series (0), and re-accessing @foo[0], say, increments $n for @foo[0]'s closure, whereas I want it to be static indicator of ordinal position in the series.

Given what you said about the sequence operator (...) trying to invoke my closure, I realized that what I need is the equivalent of prime (') in CL/Scheme, and to properly scope the ordinal incrementor $n.

So this is my solution...

my @foo = { state $n=-1; $n++; sub ($x,$y) { $x+$y+$n } } ... *;
...which when accessed in the following manner...
for 0..2 -> $i { for 0..2 { say @foo[$i](3,5); } say; }
...will produce the following output...
8 8 8 9 9 9 10 10 10

Replies are listed 'Best First'.
Re^3: Perl6 lazy list of code blocks
by moritz (Cardinal) on May 24, 2012 at 07:08 UTC
    Your first suggestion...
    my @blocks := (0..*).map: -> $n { -> $x, $y { $x * $y * $n } };
    ...seems just right, but it hangs rakudo-star-2012.04.

    It does not hang on my machine, also tested with rakudo star 2012.04.

    One way it could possibly hang on yours is if you use it in the interactive shell (REPL). Because that tries to get a string representation of the return value (here the lazy list), and that doesn't work for an infinite list. It would be nicer to not hang, but detecting if a lazy list is infinite is a tricky business.

    If you still want to use the REPL, you can just but another statement after it on the same line:

    > my @blocks := (0..*).map: -> $n { -> $x, $y { $x * $y * $n } }; 1; 1

    That way the 1 at the end is converted to a string, not the infinite list.

      I'm not using the REPL. Curious. I think I'll file a rakudo bug report. Thanks.
Re^3: Perl6 lazy list of code blocks
by aes (Initiate) on May 23, 2012 at 21:06 UTC

    I found a bug. Using...

    my @foo = { state $n=-1; $n++; sub ($x,$y) { $x+$y+$n } } ... *;

    ...in my sequential access code example from my previous post, the state variable $n seemed to maintain the ordinal position of each closure in the series, but it hid the bug of $n being instead a high-water mark for positional access, and so...

    my $foo_0 = @foo[0].(3,5); my $foo_1 = @foo[1].(3,5); my $foo_2 = @foo[2].(3,5);

    ...produces...

    10 10 10

    ...when what I desired was...

    8 9 10

    Thus, after an additional scope trick to lexically package (in $p) the persistent state value (in $n), this is my better solution...

    my @foo = { state $n=-1; $n++; my $p=$n; sub ($x,$y) { $x+$y+$p } } .. +. *;
        Ah, but you're repeating the sequential access behavior that hides the bug. Try instead reversing the access order and you'll see the "high water mark" bug.
        say @foo[2].(3,5); say @foo[1].(3,5); say @foo[0].(3,5);
        ...produces...
        10 10 10