これはMoritz Lenz氏のWebサイトPerlgeek.deで公開されているブログ記事"Perl 5 to 6" Lesson 28 - Curryingの日本語訳です。
原文はCreative Commons Attribution 3.0 Germanyに基づいて公開されています。
本エントリにはCreative Commons Attribution 3.0 Unportedを適用します。
Original text: Copyright© 2008-2010 Moritz Lenz
Japanese translation: Copyright© 2011 SATOH Koichi
NAME
"Perl 5 to 6" Lesson 28 - カリー化
SYNOPSIS
use v6;
my &f := &substr.assuming('Hello, World');
say f(0, 2); # He
say f(3, 2); # lo
say f(7); # World
say <a b c>.map: * x 2; # aabbcc
say <a b c>.map: *.uc; # ABC
for ^10 {
print <R G B>.[$_ % *]; # RGBRGBRGBR
}
DESCRIPTION
カリー化、あるいは部分適用とは関数やメソッドにいくつかの引数を与えて関数を生成する処理のことです。 これは打鍵数を節約し、また他の関数にコールバック関数を渡したいときに便利です。
"Hello, World"
から簡単に部分文字列を取り出せる関数が欲しいと仮定しましょう。古典的なやり方は専用の関数を書くことです:
sub f(*@a) {
substr('Hello, World', |@a)
}
assuming
によるカリー化
Perl6のコードオブジェクトはassuming
メソッドを持ちます。これは呼び出し元のコードオブジェクトに引数を適用し、その部分適用された関数を返します。
my &f := &substr.assuming('Hello, World');
これでf(1, 2)
がsubstr('Hello, World', 1, 2)
と等価になります。
演算子は単に変な名前のサブルーチンなので、assuming
は演算子に対しても使えます。
与えられた数に2を足すサブルーチンが欲しければ次のように書けます
my &add_two := &infix:<+>.assuming(2);
しかしこれは長ったらしすぎるので、別の方法があります。
Whatever-Starによるカリー化
my &add_two := * + 2;
say add_two(4); # 6
このアスタリスクスはWhateverと呼ばれ、引数のプレースホルダです。したがって式全体はクロージャを返します。
複数のWhateverを1つの式に含めることもでき、その場合*
の項を形式的パラメータで置き換え、複数の引数を取るクロージャが作られます。
つまり* * 5 + *
は-> $a, $b { $a * 5 + $b }
と等価です。
my $c = * * 5 + *;
say $c(10, 2); # 52
2番目の*
は項ではなく中置演算子なのでWhateverによるカリー化の対象ではないことに注意して下さい。
Whateverを使った式のクロージャへの昇格は構文に基づいてコンパイル時に行われます。これはつまり
my $star = *;
my $code = $star + 2
はクロージャを生成せず、次のようなメッセージを出してdie
するということです。
Can't take numeric value for object of type Whatever
Whateverによるカリー化にはassuming
よりも多様な使い方があります。最初の引数以外も簡単にカリー化できるからです:
say ~(1, 3).map: 'hi' x * # hi hihihi
これは文字列繰り返し演算子であるinfix:<x>
の第2引数をカリー化しているので、数値引数で呼び出されるとその数だけhi
を連結した文字列を生成するクロージャを返します。
メソッドの呼び出し元オブジェクトをWhateverにすることもできます。よって
say <a b c>.map: *.uc; # ABC
は引数に対してuc
メソッドを呼び出すクロージャになります。
MOTIVATION
Perl5で関数プログラミングができることはMark Jason DominusがHigher Order Perlで明らかにしています。
Perl6はこれをもっと簡単にしようと試みており、関数プログラミングの典型的な構造を作るための使い易いツールを提供しています。
カリー化とクロージャの容易な生成は関数プログラミングの鍵となるもので、例えばmap
やgrep
と組み合わせて使うデータ変換を非常に簡単に書けるようにします。
コメント
コメントを投稿