Attribute::Generator - Perlでジェネレータを作りたい!
Pythonにジェネレータって仕組みがありますね。 簡単に言うと、「値を返しつつ、途中から再開出来る関数」。 ジェネレータを実行すると、イテレータを返して、それに対してnextメソッドを呼ぶ度に 次の yield まで進んで、yieldの引数を nextの返値として返してくれます。
そういうのをPerlでやりたくて、 Iterator::Simple とかを作ってたのですが、 実行状態の保存をクロージャで自前実装しなきゃいけなかったりで、結構めんどう でした。
なんとなく解決出来そうな気がしたので、勢いで実装して Attribute::Generator というモジュールをCodeReposに上げました。
使い方は簡単。適当な関数にGeneratorアトリビュートつけて、 その中で yield 呼ぶだけです。
use Attribute::Generator;
sub fib:Generator {
my($x, $y) = (0, 1);
while(1) {
yield $y;
($x, $y) = ($y, $x+$y);
}
}
まず。fib() を実行してイテレータを得ます。
my $iter = fib();
あとは $iter->next する度に、1, 1, 2, 3, 5, 8, 13, 21, 34, ... と値を返してきます。 Iterator::Simpleと違って、yieldの直後から再開します。whileの途中からでも問題ありません。 クロージャでごにょごにょする必要もありません。
しかし・・・
遅いです(泣)。うちの環境で 50 万回 next 呼ぶのに 7秒くらいかかります。 こういうのって、メモリに乗り切らないくらい大量のデータを一つ一つ処理したい時に 使うことが多いのに、これでは使いものになりません(泣)
バックエンドに Coro::State というモジュール使って、関数の実行状態を保存しつつ メインロジックと行ったり来たりして実装してるのですが、そのスイッチに時間がかかるみたい。
どうしようもないかなー。誰か助けてください><
Coro::State については、また今度書けたら書きます。
トラックバック(0)
このブログ記事を参照しているブログ一覧: Attribute::Generator - Perlでジェネレータを作りたい!
このブログ記事に対するトラックバックURL: http://www.fs-output.com/rintaro/mt/mt-tb.cgi/28

コメントする