sub make_iter { my @values = @_; my $idx = -1; return sub { # check if we are out of values, # return a value or undef if we're out return (++$idx > $#values) ? undef : $values[$idx]; } } my $iter = make_iter(3,4,6,7); print while( $_ = $iter->() ); #### sub make_iter_deeper { my @AoA = @_; my @idx; my $i = 0; # keeping it simple $idx[0] = -1; # same as $idx = -1 above; my @return; return sub { # if the index of the array i'm working in is # past the end of elements if ( ++$idx[$i] > $#{@{$AoA[$i]}} ) { return; } # if not, put the next element in the return value else { $return[$i] = $AoA[$i][$idx[$i]] } return @return; } } my $iter = make_iter_deeper([3,4,6,7]); print join(',',@_) . "\n" while( @_ = $iter->() ); #### sub make_iter_deeperer { my @AoA = @_; my @idx; my $i = -1; $idx[0] = -1; my @return; return sub { # depth first to produce "nested" result behavior # if we aren't at the end of AoA's elements, go to # the next, reseting the next elements' index if( $i < $#AoA ) { $idx[++$i]= -1; } LOOP: { if ( ++$idx[$i] > $#{@{$AoA[$i]}} ) { # if the index of the array i'm working in is # past the end of elements it means we need to # go up a level and clear the last return value pop @return; # we may have finished everything return if --$i < 0; # we may have finished more than one # so check again redo LOOP; } # if not, put the next element in the return value else { $return[$i] = $AoA[$i][$idx[$i]] } } return @return; } } #### sub _NL_Iter { my( $loops, $code, $when )= @_; my @list; my $i= -1; my @idx; my @vals= @$loops; return sub { return } if ! @vals; return sub { while( 1 ) { # Prepare to append one more value: if( $i < $#$loops ) { $idx[++$i]= -1; if( isa( $loops->[$i], 'CODE' ) ) { local( $_ )= $list[-1]; $vals[$i]= $loops->[$i]->(@list); } } ## return if $i < 0; # Increment furthest value, chopping if done there: while( @{$vals[$i]} <= ++$idx[$i] ) { pop @list; return if --$i < 0; } $list[$i]= $vals[$i][$idx[$i]]; my $act; $act= !ref($when) ? $when : do { local( $_ )= $list[-1]; $when->(@list); }; return @list if $act; } }; }