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が実際に得意とする関数型プログラミングの種類に興味がある場合は、BookHigher-OrderPerlをお勧めします。

于 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 に答える