Cody Pendant has asked for the wisdom of the Perl Monks concerning the following question:

I was working on something the other day where I had two levels of recursion, like this:
for(1 .. 10){ for(a .. c){ #do something } }
and then I realised I had to add another level so it was like this:
for( 1 .. 10 ){ for( a .. c ){ for( x .. z ){ #do something } } }
and I started thinking, is it possible to write code in perl where you could recurse as many times as required? In other words, could you write a sub that would work like this:
do_my_recursion('1 .. 10'); # or do_my_recursion('1 .. 10','a .. c'); # or do_my_recursion('1 .. 10','a .. c','x .. y'); # and so on
and if so how?

I don't actually need the answer to this question in any way, I should say, I'm just wondering about it as a purely theoretical thing.



($_='kkvvttuubbooppuuiiffssqqffssmmiibbddllffss')
=~y~b-v~a-z~s; print

Replies are listed 'Best First'.
Re: Arbitrary Levels Of Recursion?
by ikegami (Patriarch) on Apr 01, 2005 at 02:10 UTC

    Have a look at NestedLoops in Algorithm::Loops

    NestedLoops( [ [ 1 .. 10 ], [ 'a' .. 'c' ], [ 'x' .. 'y' ], ], \&do_something );
      The code in 444056 is equivilent to:
      for my $a ( 1 .. 10 ){ for my $b ( a .. c ){ for my $c ( x .. z ){ do_something($a, $b, $c); } } }
      -- gam3
      A picture is worth a thousand words, but takes 200K.
Re: Arbitrary Levels Of Recursion?
by moot (Chaplain) on Apr 01, 2005 at 02:13 UTC
    That looks like iteration, not recursion.. all of your examples simply call do_my_recursion() with varying length lists.
      But in the bit that only exists in my brain, they get added as another level of recursion!


      ($_='kkvvttuubbooppuuiiffssqqffssmmiibbddllffss')
      =~y~b-v~a-z~s; print
Re: Arbitrary Levels Of Recursion?
by Random_Walk (Prior) on Apr 01, 2005 at 13:11 UTC

    This kind of does what you want for arbitary levels and it really recurses.

    #!/usr/bin/perl use warnings; use strict; sub curse { my $arrays = shift; my $index = shift || 0; my $list = shift || []; my $handling = $arrays->[$index]; print "cursing ", scalar @$arrays, " level(s)\n" unless $index; foreach (@$handling) { push @$list, $_; if (($index+1) < @$arrays) { recurse($arrays, ($index+1), $list) } else { print +(join ",",@$list), $/; } pop @$list; } print $/ unless $index; } *recurse=\&curse; # sorry, my little joke ;) my @a=qw(this that); my @b=qw(foo bar baz); my @c=(1..3); my @d=qw(how many roads); curse([\@a]); curse([\@a, \@b]); curse([\@a, \@b, \@c]); curse([\@a, \@b, \@c, \@d]);

    Cheers,
    R.

    Pereant, qui ante nos nostra dixerunt!
Re: Arbitrary Levels Of Recursion?
by Madams (Pilgrim) on Apr 04, 2005 at 04:00 UTC
    Even easier see tilly's solution in "...perils of porting...".
    I took me a while to actually wrap my head around what goes on in that snippet ;)


    qq/madams55075.spamtrap.@comcast.net/ =~ s/\.spamtrap\.//;

Re: Arbitrary Levels Of Recursion?
by TedPride (Priest) on Apr 01, 2005 at 07:48 UTC
    This is rather ridiculously easy, actually:
    use strict; use warnings; comb('',[1..10],['a'..'c'],['x'..'z']); sub comb { if ($#{@_} == 1) { print "$_[0]$_\n" for @{$_[1]}; } else { comb($_[0].$_, @_[2..$#{@_}]) for @{$_[1]}; } }
Re: Arbitrary Levels Of Recursion?
by tlm (Prior) on Apr 01, 2005 at 02:50 UTC

    Here's one (pretty clunky, but serviceable) way:

    use strict; my @who = ('Colonel Mustard', 'Miss Scarlet', 'Professor Plum'); my @where = ('library', 'billiard room', 'conservatory', 'kitchen'); my @how = ('lead pipe', 'wrench', 'candlestick', 'rope'); sub hunch { printf "%s in the %s with the %s\n", @_ } curse_again(\&hunch, [], \@who, \@where, \@how); sub curse_again { die "bad args\n" if @_ < 2; my $sub = shift; my $args = shift; return $sub->( @$args ) unless @_; my $list = shift; curse_again( $sub, [ @$args, $_ ], @_ ) for @$list; } __END__

    the lowliest monk

Re: Arbitrary Levels Of Recursion?
by DrHyde (Prior) on Apr 01, 2005 at 11:47 UTC
    I see no recursion.
      There is no recursion, just nested loops as you suspect.

      For the OP's benefit, this is a recursive way to traverse a binary tree using 'depth first':
      my $tree = init_tree(); # not shown here my $new_tree = traverse($tree); sub traverse { my $tree = shift; if (defined($tree->{left})) traverse($tree); } if (defined($tree->{right})) traverse($tree); } # .. do stuff return $tree; }