このページには、Scheme?のcall/ccについてのノウハウを集める予定。
尚、書き手の主観が反映されている為、必ずしも正しい内容が書かれているという保証は無し。
(call/cc
(lambda (cont)
...
...
...))
(call/cc
(lambda (return)
...
...
...))
結論:
call/ccで生成した継続を、call/ccの外に持ち出すような使い方をまとめて、ここでは「魔術的用法」と呼ぶ事にする。
「魔術的用法」で継続を用いる場合、コード全体が三つのパーツに分割される。
この性能を利用する事で、普通に実装する事が難しい、種々の「機能」を実装する事ができる。
(define-syntax backtrack/values
(syntax-rules ()
((_ . initial-values)
(let1 backtrack-point #f
(receive backtrack-values (let/cc cont
;; このset!はletrec用途なので副作用無し
(set! backtrack-point cont)
(values . initial-values))
(apply values backtrack-point backtrack-values))))))
(receive (backtrack n m) (backtrack/values 0 20)
;; ↑nには0が、mには20が渡される。
;; backtrackを実行すると、ここに戻ってくる。
;; そして、backtrackを実行した際の引数がnとmに新しく渡される。
;; (nとmの値が初期値かどうかで、初回実行かバックトラックかを判別できる)
;; 戻ってきた後でも、backtrackは変化しない。
;; (何回でもbacktrackを再利用できる)
(print n)
(when (< n m)
;; ↓で、receiveのところまで戻る。
(backtrack (+ 1 n) m))
(print "done."))
バックトラックを、バックトラックと意識せずに書けるようにしたもの。多分。
基本的には、プログラムの実行される実行手順構造自体を総当たり検索し、条件にマッチする値を探すような挙動を行う。上手く説明しづらいが。
あとで書く。
あとで書く。
あとで書く。
あとで書く。
外部サイトへのリンク。