#!/usr/bin/perl
use strict;
use warnings;
use List::MoreUtils 'uniq';
my %functiontable =();
$functiontable{foo} = \&foo;
sub iterate {
my ($function, $iterations, $argument) = @_;
return $argument unless 0 < $iterations;
return $argument unless $function = $functiontable{$function};
my @functioned = $function->($argument);
my @refunctioned = ();
for my $i (0 .. @functioned - 1) {
push @refunctioned, iterate ($function, ($iterations - 1), $functioned[$i]);
}
return uniq @refunctioned;
}
sub foo {
my ($argument) = @_;
my @list = ($argument, $argument.'.', $argument.',');
return @list;
}
my @results = iterate 'foo', 2, 'the';
print "@results";
This prints the the. the,
, i.e. it doesn't iterate (recurse). I would expect it to print the the. the, the.. the., the,. the,,
.
(I used Smart::Comments to check whether it enters iterate
a second time, and it does, but it doesn't seem to do everything in the function.)
I can't figure out why. Can someone please help me figure out why, or propose a fix?
The first time your subroutine iterate
is called it translates the subroutine name in $function
from a name to a subroutine reference
So the first time iterate
calls itself it is passing the subroutine reference, and the line
return $argument unless $function = $functiontable{$function};
will stringify the reference and attempt to find an element of the hash using a key something like CODE(0x23e0838)
Clearly that element doesn't exist, so your unless
fails and $argument
is returned immediately without continuing the recursion
I would write something like this
#!/usr/bin/perl
use strict;
use warnings;
use 5.10.0;
my %functions = ( foo => \&foo );
sub iterate {
my ($func, $arg, $depth) = @_;
return $arg unless $depth;
map {iterate($func, $_, $depth - 1); } $functions{$func}->($arg);
}
sub foo {
my ($arg) = @_;
map "$arg$_", '', '.', ',';
}
my @results = iterate('foo', 'the', 2);
say "@results";
the the. the, the. the.. the., the, the,. the,,