perl - How to use a nested closure as the first argument to List::Util::reduce? -


nb: closure featured in question convenient example; 1 i'm working substantially more complex this. iow, please disregard details of closure; matters, afaict, refers lexical variables in parent scope.


i want redefine sub foo below first argument in call list::util::reduce replaced reference nested closure.

use strict; use warnings fatal => 'all'; use list::util;  sub foo {   ( $x, $y ) = @_;   return list::util::reduce { $y->[ $b ]{ $x } ? $a + ( 1 << $b ) : $a } 0, 0 .. $#$y; } 

my first attempt this:

sub foo {   ( $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 results in warning saying variable "$y" not stay shared.

i've seen sort of error before, , way know around replace nested sub definition anonymous sub assigned variable. therefore, tried instead:

sub foo {   ( $x, $y ) = @_;   $z = sub {     our ( $a, $b );     return exists $y->[ $b ]{ $x } ? $a | ( 1 << $b ) : $a;   };   return list::util::reduce( $z, 0, 0 .. $#{ $y } ); } 

now error says type of arg 1 list::util::reduce must block or sub {} (not private variable).

this don't understand. why passing subref first argument reduce not supported?


ps: following work:

sub foo {   ( $x, $y ) = @_;   $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 know (a) what's wrong using subref first argument list::util::reduce (e.g. there technical impediment supporting variant?); , (b) there more direct approach (than { $z->( $a, $b ) }) passing list::util::reduce nested closure?

reduce has prototype of &@. means calls must use 1 of following syntax:

reduce block list reduce sub block, list  # first form short this. reduce \&name, list reduce \&$name, list    # same third form, via reference (short form) reduce \&block, list    # same third form, via reference (long form) 

you use of following equivalent statements:

return reduce { exists $y->[ $b ]{ $x } ? $a | ( 1 << $b ) : $a } 0, 0 .. $#$y; 

# long way of writing first. return reduce(sub { exists $y->[ $b ]{ $x } ? $a | ( 1 << $b ) : $a }, 0, 0 .. $#$y); 

my $z = sub { exists $y->[ $b ]{ $x } ? $a | ( 1 << $b ) : $a }; return reduce(\&$z, 0, 0 .. $#$y); 

you have option of overriding prototype.

my $z = sub { exists $y->[ $b ]{ $x } ? $a | ( 1 << $b ) : $a }; return &reduce($z, 0, 0 .. $#$y); 

Comments