PerlにLambda Calculusが入っているというのは以前何度か紹介した通りだが、実はMonadも入っているのである。そして、皆さんも知らない間に使っているのである。
檜山正幸のキマイラ飼育記 - 世界で一番か二番くらいにやさしい「モナド入門」「なら、予備知識ゼロでモナドの説明をしてやろうじゃねーか」と。
それでは、世界で一番Monadが簡単に使える言語(0番はPerl6!)での実例をいくつかお見せする。
まずは一番簡単な例から。
use strict; use warnings; package Tie::Verbose; use Tie::Scalar; use base 'Tie::StdScalar'; sub TIESCALAR{ my $pkg = shift; my $scalar = shift; bless \$scalar, $pkg; } sub STORE { my $self = shift; my $value = shift; $$self = $value; print "value of $self = $value\n"; $self; } 1; package main; my $m; sub fact{ my $n = shift; $m = $n <= 1 ? 1 : $n * fact($n-1); } fact(10); tie $m, 'Tie::Verbose' # $t is now monad! fact(10); # now see what happens!
最初のfact()では何も表示されないが、次のtieしたとたんに、次のfact()では代入される都度その値が出力される。計算の結果はtieしなかった時とまるで変わらない、すなわち参照透過であるが、値が出力されるという副作用がきちんと発生している。
GDBMやBerkeley DBへのtieというのは、日頃普通に使っていると思うが、これも「DBMに保存されるという副作用を持つMonad」と解釈すればいいのだ。Perlのtieは、基本的にはMonadなのである。
結局Monadを実装するためには、値と副作用を別々に保持し、値に関しては参照等価性を保ちさえすればいい。実はこれはOOでやった方が、ずっと楽である。それを今からお見せする。
# use strict; use warnings; package Monad::Maybe; use overload q("") => sub { $_[0]->{value} }, fallback => 1; sub new{ my $pkg = shift; my $value = shift; bless { value => $value, state => undef }, $pkg; } sub Maybe { __PACKAGE__->new(@_) } sub Monadic{ my $coderef = shift; sub { my $op0 = shift; my $op1 = shift; return $op0 unless $op0->{value}; # Nothing no warnings; $op0->{value} = eval{ $coderef->($op0->{value}, $op1->{value}); }; if ($@){ $op0->{state} = $@; $op0->{value} = undef; } $op0; } } # package main; my $mdiv = Monadic(sub{ $_[0] / $_[1] }); no warnings; 'unintialized'; print $mdiv->(Maybe(1), Maybe(1)), "\n"; print $mdiv->(Maybe(1), Maybe(0)), "\n"; print $mdiv->(Maybe(1), Maybe(2)), "\n"; print $mdiv->($mdiv->($mdiv->(Maybe(1), Maybe(2)), Maybe(0)), Maybe(1)), "\n";
これは、見ての通り、HaskellのMaybeを実装したものである。printの2行目と4行目に注目して欲しい。0で割っているのに、演算はこともなげに進んでいる。そしてobjectであるにも関わらず、overloadのおかげであたかも普通の数値のように出力されている。
こうして見れば、Monadが恐るるに足りないことは分かるだろう。中級以上のPerl Userは、実はすでにMonadを知っているのである。別の名前で呼んでいるだけで。
もちろん関数的にMonadを実装するのもそれほど難しくない。以下にそのものずばりのLinkを張っておく。もっとも見てのとおり、この人のPerl Codeはあまり流暢ではないけど、意味は充分汲み取れるはずだ。
もっとも、モナド則を満たしたreturn (monad constructor)と>>= (bind operator) がないと、Monadしている気になれないという人もいるだろう。実は今Monad::シリーズのModuleを片手間にこさえているところだ。きりのいいところで公開することになるだろう。あまり期待しないでお待ちいただきたい。
Dan the Monadic Perl Monger
このブログにコメントするにはログインが必要です。
さんログアウト
この記事には許可ユーザしかコメントができません。