さらに継続を渡して
find-foldからfind-fold2にすることで、procを継続渡し方式に変更できた。
だけど、find-fold2自身は(null? lis)が真となるときに、依然として「seed(=戻り値)を返却する」というCall-Return方式になっている。
これを継続渡し方式に修正してみよう、とのこと。
(define find-fold/cont (lambda (pred? proc/cont seed lis cont) (cond ((null? lis) (cont seed)) ((pred? (car lis)) (proc/cont (car lis) seed (cut find-fold/cont pred? proc/cont <> (cdr lis) cont))) (else (find-fold/cont pred? proc/cont seed (cdr lis) cont)))))
継続手続きのcontが増えた。結果をcontに渡しさえすれば良いので、結果であるseedをcontに渡している。
あと、わざとらしく部分適用のcutを使ってみた。cutに関してはid:yagiey:20090220:1235132459を参照のこと。
さて、このfind-fold/cont使ってみる。add/contの定義はid:yagiey:20100327:1269700449を参照のこと。
gosh> (find-fold/cont odd? add/cont 0 '(1 2 3 4 5 6 7 8 9 10) print) 25 #<undef>
25はprintによるもの。
contとして引数をそのまま返す手続きを与えてみると、
gosh> (find-fold/cont even? add/cont 0 '(1 2 3 4 5 6 7 8 9 10) (lambda (_) _)) 30
contにはそれまでの計算結果が渡されてくるはずなので、結果的に計算結果が取得できるわけだな。なるほどー。
結果に2を掛けた値が欲しければ、contとして
(lambda (n) (* 2 n))
を渡せばよさそうだな。
何となく継続という概念が分かってきた気がする。
実は、find-fold/contはまだ完全な継続渡し方式になっていないそうだ。
それは、(null? lis)と(pre? (car lis))のところ。
それぞれ、戻り値を見て、どうするかを決めているから。
完全な継続渡し方式にするとこうなる、というのがコラムに書いてあるが、また今度自分で書いてみよう。
分からないこと1
戻り値を利用するのがCall-Return方式ならば、elseでの再帰はCall-Return方式なんじゃないのかな?
なんでそのことには触れないのだろう。