in reply to Perl6 Contest #2: P6 That Doesn't Look Like P5

OK, here's a version that just does the iteration, but it uses coroutines (which I just taught myself for this puzzle, so bear with me):
#!/usr/bin/pugs use v6; sub NL2 (++@loop) { coro { given (@loop.elems) { when 0 { yield [] } when 1 { @loop[0].map:{ yield [$^first] }; yield undef } default { for @loop[0] -> $first { my &rest = NL2(loop => @loop[1..Inf]); my @rest; while @rest = rest() { yield [$first, @rest]; } } yield undef; } } } } my &iter = NL2(loop => ([0..2], [3..5], [6..8])); my ($cnt, $item); say "ITER {++$cnt}: {$item.perl}" while $item = iter;
Now to add the other params . . .

Replies are listed 'Best First'.
Re^2: Perl6 Contest #2: P6 That Doesn't Look Like P5
by revdiablo (Prior) on Jun 02, 2005 at 22:27 UTC

    This is nice, except I have one small quibble. You have used map in a void context, with side effects. I usually avoid doing this, as I think it adds nothing over an equivalent for loop, other than obfuscation. So, I'd change:

    when 1 { @loop[0].map:{ yield [$^first] }; yield undef }

    To:

    when 1 { for @loop[0] { yield [$^first] } yield undef }

    Much like similar circumstances in Perl 5, not only is the for loop shorter (update: shorter only due to the semicolon, but shorter nonetheless), I also think it's clearer. The less superfluous syntax we use, the better. :-)

    Update: based on the replies, I perhaps should have added a disclaimer. This post is about style and based on my personal preferences. I was not arguing in terms of performance or functionality, merely in terms of style. My personal style preference is to favor alternatives with fewer syntax characters, all else being equal. That's the essence of what I was trying to convey.

      Using map in void context is a popular topic on Perlmonks, somewhat of a religious war à la Emacs and vi. Some previous discussion of the topic includes is the use of map in a void context deprecated ? (42 comments). Remember also that Perl 5.8.1 contained an optimization for map in a void context. I believe the conclusion reached was that "we agree to disagree", in the sense that both sides agree not to impose their beliefs on the other side. Recall also Larry's quote on the matter:
      The argument against using an operator for other than its primary purpose strikes me the same as the old argument that you shouldn't have sex for other than procreational purposes. Sometimes side effects are more enjoyable than the originally intended effect.

      This isn't as bad as you might think. Because map is being used in Void context, we know we can throw away the return value, and hence not bother to compute it in many cases due to Lazy evaluation...

      $h=$ENV{HOME};my@q=split/\n\n/,`cat $h/.quotes`;$s="$h/." ."signature";$t=`cat $s`;print$t,"\n",$q[rand($#q)],"\n";
      Good point. That was actually a holdover from when I did the non-coroutine recursive version -- the map wasn't void in that one. :-) Fixed in my working version.
Re^2: Perl6 Contest #2: P6 That Doesn't Look Like P5
by geoffb (Novice) on Jun 03, 2005 at 01:45 UTC
    Here's a version that has the $only_when and $code functionality. It's not quite what I originally aimed at because I came across at least one (and possibly more than one) Pugs bug. In particular, my next task is to write up a test case for the bug that causes the one line version of the following test from NestedLoop to die with a casting error in pugs if $only_when happens to be undef:
    return &?SUB() if $only_when and not $only_when(@next);
    Here's the code as it currently stands:
    #!/usr/bin/pugs use v6; sub NestedLoop (++@loop, +$only_when, +$code) { my &iter = NL2(loop => @loop); sub { my @next = iter; return @next unless defined @next[0]; if $only_when { return &?SUB() unless $only_when(@next); } $code(@next) if $code; return @next; } } sub NL2 (++@loop) { coro { given (@loop.elems) { when 0 { yield [] } when 1 { for @loop[0] { yield [$^first] } yield undef whi +le 1 } default { for @loop[0] -> $first { my &rest = NL2(loop => @loop[1..Inf]); my @rest; while @rest = rest() { yield [$first, @rest]; } } yield undef while 1; } } } } my ($cnt, $item); my &iter = NestedLoop(loop => ([0..2], [3..5], [6..8]), only_when => sub { ++$cnt % 2 }, code => sub {say "reversed: {reverse @^grou +p}"}); say "ITER {$cnt}: {$item.perl}" while $item = iter;
      I just added a test to pugs for the undef cast fail bug above (my first commit!), so hopefully this will be a non-issue soon.
Re^2: Perl6 Contest #2: P6 That Doesn't Look Like P5
by Limbic~Region (Chancellor) on Jun 02, 2005 at 22:12 UTC
    geoffb,
    Very cool - especially considering you just got Pugs running yesterday. I do want to point out that I believe the coroutine syntax is still unspecced as S17 hasn't been written yet. Additionally, I probably would change:
    my &rest = NL2(loop => @loop[1..Inf]); # to my &rest = NL2(loop => @loop[1..@loop.end]);
    I know p6 will DWYM, but I think it is clearer that way.

    Cheers - L~R