8

在 Perl 5 中,我们可以应用函数式编程技术(使用闭包、高阶函数,如 map、grep 等)。但是函数组合呢?比方说,在 Haskell 中,它可以很容易地用 (.) 函数完成:

map (negate . abs) [-3, 2, 4, -1, 5]

Perl 中这种“点函数”的等价物是什么?

4

4 回答 4

11

可悲的是,我不知道 Haskell。

但是函数组合本质上是将一个函数的输出作为参数放入下一个函数中。

output = (negate . abs)(input)是一样的output = negate(abs(input))。在 Perl 中,parens 通常是可选的,输入是隐含在map函数中的,所以我们可以说

output = map (negate abs) list

现在只要把它翻译成 Perl 语法,我们就有了

my @output = map {- abs} (1,2,3);

对于数学/代数否定,和

my @output = map {! abs} (1,2,3);

对于逻辑否定(当然与 相同map {! $_} (1,2,3))。

于 2012-08-20T12:50:04.307 回答
9

好的,首先让我们看一下 Haskell 中 (.) 的函数签名:

(.) :: (b -> c) -> (a -> b) -> a -> c

这很容易像这样实现

foo :: (b -> c) -> (a -> b) -> a -> c
foo f g a = f(g a)

Perl 中的实现可能看起来像这样

sub dot {
    my $f = shift;
    my $g = shift;
    my $a = shift;
    $f->( $g->($a) )
}

现在我们实现这样的negate功能

sub negate { - shift }

我们已经准备好像这样使用它了

my @foo = map { dot \&negate, sub{abs}, $_ } -2..2;
print join( ", ", @foo) . "\n";

但正如您从其他答案中看到的那样,有更简单的方法可以做到这一点。所以你真正应该问自己的是,你为什么要这么做。Haskel 有几个特性使得函数组合非常有用。然而,在 Perl 中,我觉得它真的很笨拙和尴尬。

如果您对 Perl 真正擅长的函数式编程类型感兴趣,我推荐 Book Higher-Order Perl

于 2012-08-20T13:44:15.340 回答
6

我不确定这是您正在寻找的答案:

sub negate { - $_[0] }
map { negate abs } -3, 2, 4, -1, 5
于 2012-08-20T12:47:11.573 回答
4
sub compose {
    my ( $f, $g ) = @_;
    return sub { $f->( $g->( @_ )); };
}

sub negate (_) { - ( $_[0] // $_ // 0 ); }

my $neg_abs = compose( \&negate, \&CORE::abs );

my @negs = map { $neg_abs->( $_ ) } -3, 2, 4, -1, 5;

compose将实现一个非常简单的点函数版本。但如前所述,它不是特别需要的,除非您想将该功能传输到另一个位置。

于 2012-08-20T16:23:10.307 回答