YAPC Asia 2011で話をする予定のモジュールをCPANへアップしました。
Data::Monad::CondVarはJSDeferred みたいなもんです。
use AnyEvent; use AnyEvent::HTTP; sub random_choice { my ($data, $headers, $cb) = @_; my (@url) = $data =~ m{href="(http:[^"]+)}g; http_get +(shuffle @url)[0], $cb; } my $cv = AE::cv; http_get "http://yapcasia.org/2011/", sub { random_choice @_ => sub { random_choice @_ => sub { random_choice @_ => sub { my ($data, $headers) = @_; my ($title) = $data =~ qr{<title>([^<]+)}; print $title, "\n"; $cv->send; }; }; }; }; $cv->recv;
のようにネストが深くなりがちの非同期処理を、
use AnyEvent; use AnyEvent::HTTP; use Data::Monad::CondVar; sub random_choice { my ($data, $headers) = @_; my (@url) = $data =~ m{href="(http:[^"]+)}g; as_cv { http_get +(shuffle @url)[0], $_[0] }; } as_cv { http_get "http://yapcasia.org/2011/", $_[0] } ->flat_map(\&random_choice) ->flat_map(\&random_choice) ->flat_map(\&random_choice) ->map(sub { my ($data, $headers) = @_; my ($title) = $data =~ qr{<title>([^<]+)}; print $title, "\n"; })->recv;
のようにネストせずに書けるようにするものです。
Data::Monad はData::Monad::CondVar のモナドの実装部分を抽出したもので、Listモナドとかが実装されてます。
use Data::Monad::List; use Data::Monad::Base::Sugar; my $result = Data::Monad::Base::Sugar::for { pick \my $x => sub { scalar_list 1 .. 100 }; pick \my $y => sub { scalar_list $x .. 100 }; pick \my $z => sub { scalar_list $y .. ($x + $y > 100 ? 100 : $x + $y) }; satisfy { $x**2 + $y**2 == $z**2 }; yield { $x, $y, $z } }; print join(',', @$_), "\n" for $result->values; # 3,4,5 # 5,12,13 # ... # 60,80,100 # 65,72,97
モナドとして実装したいものがあれば、Data::Monad::Base::Monad を継承して作ると、map*1やflatten*2、sequence 辺りのメソッドが自動生成されたり、for構文が使えたりします。
StateモナドやらContモナドやらは、Monad Transformerまで定義するかで迷ってるのでまだ入れてないです。
詳細はトークの中で。