Perl - 向子块发送块时的最佳实践

Chr*_*fer 4 perl

我是函数式编程的忠实粉丝,所以当我在Perl中发现块引用时,我开始大量使用它们.

但是,我编写的以块为参数的函数是用这种样式编写的:

sub mygrep (&@) {
    my $code = shift;
    my @result;
    foreach $_ (@_) {
        push(@result, $_) if &$code;
    }
    @result;
}
Run Code Online (Sandbox Code Playgroud)

(来自http://perldoc.perl.org/perlsub.html#Prototypes)

本质上,我的大部分功能$_都是为了让代码块能够访问我的sub中的数据而设置的.我想我的问题可以分为三个子问题:

  1. 这种方法有一些重大缺陷吗?
  2. 它是一个更好的主意localIZE $_设置之前?
  3. 我应该使用部分应用的功能吗?

我仍然是一个Perl新手所以任何答案和建议都表示赞赏 - 提前感谢!:)

Eri*_*rom 5

在您编写的代码中:

sub mygrep (&@) {
    my $code = shift;
    my @result;
    foreach $_ (@_) {
        push(@result, $_) if &$code;
    }
    @result;
}
Run Code Online (Sandbox Code Playgroud)

foreach循环是隐含在本地化$_上的每个循环迭代变量.它是完全安全的(并且是获得$_正确值的最快方法).

我对上面代码的唯一要点是,每次&$code执行时,它都可以访问源参数列表,这可能会导致错误.您可以按如下方式重写代码:

sub mygrep (&@) {
    my $code = shift;
    my @result;
    foreach $_ (splice @_) {
        push(@result, $_) if &$code;  # @_ is empty here
    }
    @result;
}
Run Code Online (Sandbox Code Playgroud)

以下是您可以编写该功能的其他几种方法:

sub mygrep (&@) {
    my ($code, @result) = shift;
    &$code and push @result, $_ for splice @_;
    @result
}

sub mygrep (&@) {
    my $code = shift;
    # or using grep in our new grep:
    grep &$code, splice @_
}
Run Code Online (Sandbox Code Playgroud)

这些示例中的每一个$_都为其子例程提供了别名,并具有适当的本地化.

如果您对高阶函数感兴趣,我建议您查看我的模块List :: Gen on CPAN,它提供了许多高阶函数来操作实数和惰性列表.

use List::Gen;

my $list = filter {$_ % 2} <1..>;

# as a lazy array:
say "@$list[0 .. 5]"; # 1 3 5 7 9 11

# as an object:
$list->map('**2')->drop(100)->say(5); # 40401 41209 42025 42849 43681

zip('.' => <a..>, <1..>)->say(5);  # a1 b2 c3 d4 e5
Run Code Online (Sandbox Code Playgroud)