NB: the closure shown in this question is just a convenient example; the one I actually work with is significantly more complicated than that. IOW, please ignore the details of this closure; all that matters, AFAICT, is that it refers to lexical variables in the parent area.
I want to override sub foo
below so that the first argument in the List::Util::reduce
call is replaced with a nested closure reference.
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:
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 leads to a warning that Variable "$y" will not stay shared
.
I have seen such an error before, and the only way I know around it is to replace the nested sub
definition with the anonymous submenu assigned to the variable. So I tried this:
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)
.
I really do not understand this. Why isn't passing subref as the first argument to reduce
?
PS: the following works:
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 is wrong with using subref as the first argument for List::Util::reduce
(for example, is there any technical obstacle to supporting this option?); and (b) is there a more direct approach (than { $z->( $a, $b ) }
) to switching to List::Util::reduce
nested closure?