NB: the closure featured in this question is just a convenient example; the one I'm actually working with is substantially more complex than this. IOW, please disregard the details of this closure; all that matters, AFAICT, is that it refers to lexical variables in the parent scope.
I want to redefine the sub foo below so that the first argument in the call to List::Util::reduce is replaced with a reference to a nested closure.
use strict;
use warnings FATAL => 'all';
use List::Util;
sub foo {
my ( $x, $y ) = @_;
return List::Util::reduce { $y->[ $b ]{ $x } ? $a + ( 1 << $b ) : $a } 0, 0 .. $#$y;
}
My first attempt was this:
sub foo {
my ( $x, $y ) = @_;
sub z {
our ( $a, $b );
return exists $y->[ $b ]{ $x } ? $a | ( 1 << $b ) : $a;
}
return List::Util::reduce \&z, 0, 0 .. $#{ $y };
}
...but this results in a warning saying that Variable "$y" will not stay shared.
I've seen this sort of error before, and the only way I know around it is to replace the nested sub definition with an anonymous sub assigned to a variable. Therefore, I tried this instead:
sub foo {
my ( $x, $y ) = @_;
my $z = sub {
our ( $a, $b );
return exists $y->[ $b ]{ $x } ? $a | ( 1 << $b ) : $a;
};
return List::Util::reduce( $z, 0, 0 .. $#{ $y } );
}
Now the error says Type of arg 1 to List::Util::reduce must be block or sub {} (not private variable).
This I really don't understand. Why would passing a subref as the first argument to reduce not be supported?
PS: The following does work:
sub foo {
my ( $x, $y ) = @_;
my $z = sub {
our ( $a, $b );
return exists $y->[ $b ]{ $x } ? $a | ( 1 << $b ) : $a;
};
return List::Util::reduce { $z->( $a, $b ) } 0, 0 .. $#{ $y };
}
...but I really would like to know (a) what's wrong with using a subref as the first argument to List::Util::reduce (e.g. is there some technical impediment to supporting this variant?); and (b) is there a more direct approach (than { $z->( $a, $b ) }) to passing to List::Util::reduce a nested closure?