closures - 如何使用嵌套闭包作为 List::Util::reduce 的第一个参数?

标签 closures perl

注意:这个问题中的闭包只是一个方便的例子;我实际上正在使用的那个比这要复杂得多。 IOW,请忽略此关闭的详细信息; AFAICT 最重要的是它引用父作用域中的词法变量。

我想重新定义子 foo下面,以便调用 List::Util::reduce 中的第一个参数替换为对嵌套闭包的引用。

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;
}

我的第一次尝试是这样的:
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 };
}

...但这会导致警告说 Variable "$y" will not stay shared .

我以前见过这种错误,我知道的唯一方法是替换嵌套的 sub将匿名子分配给变量的定义。因此,我尝试了这个:
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 } );
}

现在错误显示Type of arg 1 to List::Util::reduce must be block or sub {} (not private variable) .

这个我真的不明白。为什么要将子引用作为第一个参数传递给 reduce不被支持?

PS:以下确实有效:
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 };
}

...但我真的很想知道 (a) 使用子引用作为 List::Util::reduce 的第一个参数有什么问题(例如,支持此变体是否存在一些技术障碍?); (b) 是否有更直接的方法(比 { $z->( $a, $b ) } )传递给 List::Util::reduce嵌套闭包?

最佳答案

List::Util::reduce使用 Perl 原型(prototype),它指定对调用中传递的参数进行编译时检查。传递包含子例程引用的标量变量在编译时无法验证,因此 Perl 不允许它

这也是解决问题的途径。使用 & 字符调用子程序通常被认为是不好的做法 &但在这种情况下,它会破坏原型(prototype)检查,这是必需的

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 } ); # Defeat prototype
}

请注意,这通常是不可能的,因为原型(prototype)可以执行诸如强制数组或散列通过引用传递,或强制表达式上的标量上下文以及使用 & 调用此类子例程之类的事情。也会禁用这些行为。但是reduce原型(prototype)为 &@这意味着一个 block 或sub { } (sub 部分在这里是可选的)后跟标量列表,这是没有原型(prototype)的子程序的正常行为,因此唯一的效果是允许 $z传递给子程序引用

关于closures - 如何使用嵌套闭包作为 List::Util::reduce 的第一个参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36237274/

相关文章:

Perl SOAP::LITE——无法验证?

perl - Devel::Cover 测试覆盖选项

swift - 为什么UIView动画闭包中的弱自引用导致Swift编译错误

javascript - "function incrementNumber()"括起来的括号是可选的吗?

macos - 类似于 nodemon 的工具,用于 perl

perl - 在Perl中,未初始化的哈希键的默认值为零吗?

循环内的 JavaScript 闭包 – 简单的实际示例

javascript - 此 JavaScript 代码返回 'Undefined'

go - 使用命名返回类型时未使用变量

perl - 如何加快 Perl 处理固定宽度数据的速度?