TL;DR

Let’s go past fixed arrays in nested loops and allow for dynamically generate them based on the specific position on the loop.

One thing that NestedLoops allows doing is to pass sub references instead of array references to dynamically generate the items in a specific layer. This allows, for example, doing something like this (taken from the module’s documentation):

use Algorithm::Loops qw( NestedLoops );
my $depth= 3;
NestedLoops(
    [   [ 0..$N ],
        ( sub { [$_+1..$N] } ) x ($depth-1),
    ],
    \&Stuff,
);

One unfortunate thing is that I could not find what is the exact interface of these subs, a quick look at the code seems to hint that:

  • $_ is localized with the latest value in the previous level of looping;
  • all items for all previous levels are passed through @_.

This means that the first item must always be an array reference (otherwise we could not put anything in $_). We will make the same assumption.

Without further ado… here’s the implementation of the iterator solution with this enhancement:

We’re making our implementation much closer to a recursive one, to some extent: our @indexes now tracks an explicit @stack, which contains frames with all variables that have to be dynamically evolved during the computation.

The other big change is in lines 40 to 48, where we figure out whether we have to call the sub dynamically and then put a new item onto the stack, with the right data.

Example run:

     1	A-2-Foo
     2	A-2-Bar
     3	A-2-Baz
     4	A-3-foo
    ...
    26	C-2-Bar
    27	C-2-Baz
    28	C-3-foo
    29	C-3-bar
    ...
    71	F-7-bar
    72	F-7-baz

Seems to be working!

We have been looking at the most interesting aspects of implementing NestedLoops, at least for study reasons… I guess that by now you know where to look for a solution to this kind of problems 😄