2011年3月7日月曜日

Perl 5 to 6 - カリー化

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

これは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はこれをもっと簡単にしようと試みており、関数プログラミングの典型的な構造を作るための使い易いツールを提供しています。 カリー化とクロージャの容易な生成は関数プログラミングの鍵となるもので、例えばmapgrepと組み合わせて使うデータ変換を非常に簡単に書けるようにします。

SEE ALSO

http://perlcabal.org/syn/S02.html#Built-In_Data_Types

http://hop.perl.plover.com/

http://en.wikipedia.org/wiki/Currying

0 コメント:

コメントを投稿