Perl 5では、関数型プログラミング手法を適用できます(クロージャ、map、grepなどの高階関数を使用)。しかし、関数の合成はどうですか?たとえば、Haskellでは(。)関数を使用すると非常に簡単に実行できます。
map (negate . abs) [-3, 2, 4, -1, 5]
Perlのそのような「ドット関数」に相当するものは何でしょうか?
Perl 5では、関数型プログラミング手法を適用できます(クロージャ、map、grepなどの高階関数を使用)。しかし、関数の合成はどうですか?たとえば、Haskellでは(。)関数を使用すると非常に簡単に実行できます。
map (negate . abs) [-3, 2, 4, -1, 5]
Perlのそのような「ドット関数」に相当するものは何でしょうか?
悲しいことに、私は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)
です)。
さて、最初に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をお勧めします。
これがあなたが求めていた答えかどうかはわかりません。
sub negate { - $_[0] }
map { negate abs } -3, 2, 4, -1, 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;
compose
ドット関数の非常に単純なバージョンを実装します。ただし、前述のように、関数を別の場所に転送する場合を除いて、特に必要なものではありません。