2012年5月2日水曜日

Scheme第13歩

継続の話その1。
call-with-current-continuation、略してcall/ccの基本的な使い方。
(call/cc プロシージャ)
こうすると、引数として与えられたプロシージャが実行される。…だけなら話は簡単なのだが、それではwith-current-continuationが黙っちゃいない。プロシージャを実行するとき、その引数としてその時点での継続というものが渡される。

継続とは、ある瞬間の実行環境のスナップショットのようなもの。大雑把な言い方をすると、C言語のsetjmpで取得する情報をもうちょっとリッチにしたようなもの。Cの場合、setjmpで取得した情報を使うにはlongjmpという専用の関数を使うけれど、Schemeの場合は継続そのものが関数の形で得られる。そしてその継続を普通の関数のように呼び出すと、longjmpのように行ったきり戻らない。

一例として、リストlsの中から最初に見つけた3の倍数をprintするコードを、無理矢理call/ccを使って書いたもの。
(define ls '(11 17 5 6 21 31 33))
(print (call/cc (lambda (c)
  (let loop ((l ls))
    (cond
      ((eq? ls '()) #\x)
      ((= 0 (mod (car l) 3)) (c (car l)))
      (else (loop (cdr l)))
    )
  )
)))
実行時、call/ccの引数の無名プロシージャの仮引数cには継続が入っている。なのでこのcを実行すると、どんなにループやらなにやらがネストしていようともcall/ccの呼び出し箇所、今回の例では何かprintしようとしているところに飛んでいく。

0 件のコメント:

コメントを投稿