use v6; sub _NL_Iter(@loops, $when) returns Ref { my @list; my $i = -1; my @idx; return sub { return } if ! @loops; my @vals = @loops; return sub { while 1 { # Prepare to append one more value: if $i < @loops.end { @idx[++$i]= -1; if @loops[$i].does(Code) { @vals[$i]= @loops[$i](@list[-1], @list); } } ## return if $i < 0; # Increment furthest value, chopping if done there. while @vals[$i].elems <= ++@idx[$i] { pop @list; return if --$i < 0; } @list[$i]= @vals[$i][@idx[$i]]; if $when.does(Code) { return @list if $when(@list[-1], @list); } else { return @list; } } }; } sub NestedLoop(++@loops, +$code, +$when) { my $onlywhen = $when; my $count_elems = @loops.elems + 1; $onlywhen //= sub { @_ == $count_elems }; # Default case - when we have a full count. my $iter= _NL_Iter(@loops, $onlywhen ); if ! $code { # There seeems to be no way to check for void context, since # want.count is not working. I wanted to test want.count == 0. return $iter; } my @ret; my @list; while @list = $iter() { @list = $code( @list ); if want.List { push @ret, @list; } else { @ret[0] += @list; } } return want.List ?? @ret :: ( $ret[0] // 0 ); } my $next = NestedLoop(loops => ([0..2], [0..2], [0..2])); my @group; while @group = $next() { say ~@group; }; say "\nsecond case:"; my $N = 4; my $depth = 3; my $i2 = NestedLoop(loops => ( [ 0..$N ], ( sub { [@_[0]+1..$N] } ) xx ($depth-1), ) ); while @group = $i2() { say ~@group; };