継続渡しで実行を制御する

find-foldで済むものを、なぜ手間をかけてfind-fold2にするのか。
それは外から与えられるproc/contを少しいじるだけで、find-fold2の実行を制御できるからだ、と。
ということで、コード例をば。次のようなnextとbreakとadd/breakを定義して、

(define next #f)
(define break (lambda (e) e))
(define add/break
  (lambda (elt seed cont)
    (set! next
          (lambda ()
            (print "found: " elt)
            (cont (+ elt seed))))
    (break #f)))

次のようにfind-fold2に与えてやると、面白いことが起こる。

gosh> (find-fold2 odd? add/break 0 '(1 2 3 4 5 6 7 8 9 10))
#f
gosh> (next)
found: 1
#f
gosh> (next)
found: 3
#f
gosh> (next)
found: 5
#f
gosh> (next)
found: 7
#f
gosh> (next)
found: 9
25

検索結果を1ずつ見れるようになりましたとさ。
すごい!find-fold2の定義を変更せずにこんなことが!すごい!



何が起きているのかよくわからなかったので、ちょっと追ってみた。

  • find-fold2の実行→proc/contの実行→nextを更新→#fが返る
  • REPLへ戻る
  • nextの実行→contの実行→find-fold2の実行→proc/contの実行→nextを更新→#fが返る
  • REPLへ戻る
  • nextの実行→contの実行→find-fold2の実行→proc/contの実行→nextを更新→#fが返る
  • (中略)
  • REPLへ戻る
  • nextの実行→contの実行→find-fold2の実行→proc/contの実行→nextを更新→#fが返る
  • REPLへ戻る
  • nextの実行→contの実行→find-fold2の実行→lisが空→seedが返る

なるほどねぇ...。動きは理解はできたけど、書けと言われてもちょっと無理かなぁー。