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))実行時、call/ccの引数の無名プロシージャの仮引数cには継続が入っている。なのでこのcを実行すると、どんなにループやらなにやらがネストしていようともcall/ccの呼び出し箇所、今回の例では何かprintしようとしているところに飛んでいく。
(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)))
)
)
)))
0 件のコメント:
コメントを投稿