継続渡し形式

find-foldからfind-fold2への書き換えでいきなりつまずいてたけど、やっと理解できてきたかも。
指定した条件を満たす要素だけfoldするfind-foldは、素直に書くと以下のようになる。

(define find-fold
  (lambda (pred? proc seed lis)
    (cond
     ((null? lis) seed)
     ((pred? (car lis))
      (find-fold pred? proc (proc (car lis) seed) (cdr lis)))
     (else
      (find-fold pred? proc seed (cdr lis))))))

2番目のcond節で、(car lis)とseedにprocを適用して、その結果(戻り値)でfind-foldを再帰させている。
procの結果が戻ってくるので、章のはじめにあったC社のCall-Return方式だ。
渡されたリストの中から奇数を探して、その総和を求めるには以下のようにする。

gosh> (define add
        (lambda (elt seed)
          (+ elt seed)))
add
gosh> (find-fold odd? add 0 '(1 2 3 4 5 6 7 8 9 10))
25


これに対し、S社の継続渡し方式では、

  • 計算に必要な情報(Call-Return方式でのeltとseed)
  • 計算結果を渡す宛先

を一緒に渡してやるので、以下のようになる。

(define find-fold2
  (lambda (pred? proc/cont seed lis)
    (cond
     ((null? lis) seed)
     ((pred? (car lis))
      (proc/cont (car lis)
                 seed
                 (lambda (seed2) (find-fold2 pred? proc/cont seed2 (cdr lis)))))
     (else
      (find-fold2 pred? proc/cont seed (cdr lis))))))

proc/contが

  1. eltとseedで計算(proc)をする
  2. 計算結果を次の工程(cont)に渡す

をやってくれるところで、具体的に書くと

(define add/cont
  (lambda (elt seed cont)
    (cont (+ elt seed))))

で、find-fold2で使ってみると、次のとおり。

gosh> (find-fold2 odd? add/cont 0 '(1 2 3 4 5 6 7 8 9 10))
25


計算結果を持って、ずんずんと深く入り込んでいくイメージがようやくつかめてきた。