Schemeの継続と環境

前回の記事で、call/cc は呼ばれた時点での継続を取り出してくれるということを書いたのだが、その時点での環境は保存されているのだろうか? 前回の記事に出て来た wayback 関数を少し書き換えて実験してみる。

(define cont #f)

(define (capture x)
  (call/cc (lambda (cc) (set! cont cc) x)))

(define (wayback2 n)
  (let* ((a 0) (x (capture n)))
    (display (list a x))
    (newline)
    (set! a 1)
    (if (> x 0) (cont (- x 1)) x)))

let* は前に束縛された変数を、後の変数束縛で参照したい時に使えるのだが、それゆえに実行順も決められる。ここでは、aに0が束縛された後、xに (capture n) が束縛される。capture はその時点での継続をcontに保存し、引数をそのまま返すような関数。その後、aとxを表示した後、aに1を代入する。これを実行すると、GaucheでもChibi-Schemeでも以下のような結果になった。

> (wayback2 3)
(0 3)
(1 2)
(1 1)
(1 0)
=> 0

継続 cont が呼び出されると、xへの引数の束縛以降の処理が行われるが、aへの0の束縛はそれ以前に終わっているので繰り返されない。しかし、もし継続が環境も保存しているなら、何度呼び出してもaは0に戻るはずだ。だが、結果はそうはならず、(set! a 1) の影響がその後の継続呼び出しにも反映されている。継続は環境を保存してはくれない。

評価順序と継続
ここに詳しく書いてあった。