01 月 08 日(Thu)のアレゲメモ

なんでも継続、Perl で。

最近よくコンティニュエーション・パッシングだとか、 継続ベースの○○とか、 そういう話題を耳にします。 でも継続っていうのが何なのか良く分からなかったので、 お正月休みに Shiro Kawaiさんの なんでも継続 を読んでみました。


今までずっと難しいだろうと思って読んでなかったんだけど、 これがまたとても分かりやすくて面白かったので、 途中にあげられていたサンプルコードを Perl でも書いてみました。

普通の再帰形式

Scheme では

(define (leaf-count tree)
  (if (pair? tree)
      (+ (leaf-count (car tree))
	  (leaf-count (cdr tree)))
      1))

Perl では

Perl にはペアがないので、 2 要素の配列でエミュレートすることにします。

それ以外はそのまんまです。

sub leaf_count {
    my ($tree) = @_;

    if (ref $tree) {
	 &leaf_count ($tree->[0])
	     + &leaf_count ($tree->[1]);
    } else {
	 1;
    }
}

継続渡し形式

Scheme では

(define (leaf-count/cps tree cont)
  (if (pair? tree)
      (leaf-count/cps (car tree)      
		       (lambda (n)
			 (leaf-count/cps (cdr tree)
					 (lambda (m) (cont (+ n m))))))
      (cont 1)))

Perl では

基本的には、 lambda を sub にすればいいだけだと思うけど、 sub の中に sub を書くときは、 ちょっと注意が必要みたい。(Perl のバグ?)

sub leaf_count_cps {
    my ($tree, $cont) = @_;

    if (ref $tree) {
	 &leaf_count_cps ($tree->[0],
			  sub {
			      my ($n) = @_;
			      my $dummy = $cont; # なぜか必要みたい。
			      &leaf_count_cps ($tree->[1],
					       sub {
						   my ($m) = @_;
						   $cont->($n + $m);
					       });
			  });
    } else {
	 $cont->(1);
    }
}

Scheme の values に対応する手続きを作って実行します。

my $tree = [["a", "b"], [["c", "d"], "e"]];

sub values {@_}
print &leaf_count_cps ($tree, \&values), "\n";

実行するとちゃんと 5 がでました。

ファーストクラスの継承?

call/cc を Perl で作ることはできるかなぁ。

Python 使いの田原さんは、 Zope で継続ベース風 Web アプリをつくちゃった そうなんですが、 Perl でも似たようなものは作れるかな。

「なんでも継続」の後半のまだかかれていない部分で、 C での実装にも触れられるような感じなので、 それを楽しみにしていよう。

Comments

最終更新: 2004 年 01 月 08 日 05:41