Perl中的函数组合

sig*_*agi 8 perl functional-programming

在Perl 5中,我们可以应用函数式编程技术(使用闭包,高阶函数,如map,grep等).但功能构成怎么样?让我们说,在Haskell中,可以使用(.)函数很容易地完成它:

map (negate . abs) [-3, 2, 4, -1, 5]
Run Code Online (Sandbox Code Playgroud)

在Perl中,这个"点函数"的等价物是什么?

amo*_*mon 10

可悲的是,我不知道Haskell.

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

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

output = map (negate abs) list
Run Code Online (Sandbox Code Playgroud)

现在只需将其转换为Perl语法,我们就可以了

my @output = map {- abs} (1,2,3);
Run Code Online (Sandbox Code Playgroud)

对于数学/代数否定,和

my @output = map {! abs} (1,2,3);
Run Code Online (Sandbox Code Playgroud)

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


tau*_*uli 9

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

(.) :: (b -> c) -> (a -> b) -> a -> c
Run Code Online (Sandbox Code Playgroud)

这很容易实现

foo :: (b -> c) -> (a -> b) -> a -> c
foo f g a = f(g a)
Run Code Online (Sandbox Code Playgroud)

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

sub dot {
    my $f = shift;
    my $g = shift;
    my $a = shift;
    $f->( $g->($a) )
}
Run Code Online (Sandbox Code Playgroud)

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

sub negate { - shift }
Run Code Online (Sandbox Code Playgroud)

我们准备像这样使用它

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

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

如果您对Perl实际擅长的函数式编程感兴趣,我建议使用Book Higher-Order Perl.


cho*_*oba 5

我不确定这是你要求的答案:

sub negate { - $_[0] }
map { negate abs } -3, 2, 4, -1, 5
Run Code Online (Sandbox Code Playgroud)


Axe*_*man 5

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;
Run Code Online (Sandbox Code Playgroud)

compose将实现点函数的一个非常简单的版本。但正如前面提到的,这并不是特别需要的东西,除非您想将函数传输到另一个位置。