如何在Perl中执行部分应用功能?

时间:2014-05-28 05:57:43

标签: perl

有没有办法在Perl中实现部分应用?

假设,我想做类似的事情:

sub each_file($arr, $op) {
    $op->($_) for @{$arr};
    ...
} 

sub each_line($op, $file) {
    ... 
}

each_file($arr, each_line($op));

我想部分仅将each_line()应用于$op,因此它将成为一个新功能,可以传递给$each_file,我如何用惯用的Perl表达?

3 个答案:

答案 0 :(得分:1)

您可以使用两种方法组合在Perl中执行此操作:

  • 返回函数引用的函数

  • 闭包

示例:

sub each_file {
    my ($arr, $line_fn) = @_;
    $line_fn->($_) for @{$arr};
    ...
} 

sub each_line {
    my ($op, $file) = @_;
    ... 
}

sub make_line_processor {
  my ( $op ) = @_;

  # This is closed over $op, which effectively becomes 
  # a constant for the returned function
  my $fn = sub {
     return each_line( $op, @_ );
  };
  return $fn;
}


# To call it:
each_file( $arr, make_line_processor($op) );

如果您不想直接$op,但需要一些昂贵的获取方法,这可能是一种更有用的技术。在这种情况下,您只需计算一次派生值(在make_line_processor函数中)并将其关闭。

答案 1 :(得分:1)

# given some $op as implied by your code snippet
each_file($arr, sub { each_line($op, shift) });
# shift op will be applied when anonymous sub { … } is called

(当您拨打$op电话时,您的代码段并未完全清楚您想要each_line的内容。通常情况下,提供小型工作程序会更好。)

答案 2 :(得分:0)

您可以将此功能上传到班级。然后你可以overload the subroutine dereference operator使它看起来像你的类真的是代码参考。

package Partial;

use overload '&{}' => \&call;

sub new {
    my $class = shift;
    my $code = shift;
    bless {code => $code, args => \@_}, $class;
}

sub call {
    my ($self) = @_;
    return sub{ $self->{code}->(@{$self->{args}}, @_) }
}

然后您可以像这样使用它:

sub printArgs {
    print join ", ", @_;
    print "\n";
}

my $partial = Partial->new(\&printArgs, 'foo', 'bar');
$partial->('baz', 'bat');
# prints foo, bar, baz, bat