use v6-alpha;

############################################################
# Coroutine solution by geoffb                             #
# + optional functionality in Algorithm::Loops NestedLoops #
############################################################

my @loops = ([1..3], ['a'..'e'], ['foo', 'bar']);

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 &?ROUTINE() 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 while 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;
                yield while 1;
            }
        }
    }
}


my ($cnt, $item);

my &iter = NestedLoop(loop      => @loops,
                      only_when => { ++$cnt % 2 },
                      code      => { say "reversed: {reverse @^group}" });

say "ITER {$cnt}: {$item.perl}" while $item = iter;
