継続マラソン3

今日は忘年会のためパスと行きたいところだけど何とか少しでも。

;; arinoさんからネタを頂きました
;; 率直な感想では急に難しくなりました(笑)

(define (fact n m)
  (call/cc
   (lambda (end)
     (letrec ((fact2 (lambda (n sum)
                       (if (< n m)
                           (end sum)
                           (fact2 (- n 1) (* n sum))))))
       (fact2 n m)))))

(display (fact 5 1))

;; 今までと決定的に違うのは
;;   関数の先頭でcall/cc していること
;;   letrecを使っていること
;; あたりかな。

;; 見方としては
;; call/cc = Aと置き換えると
;; (define (fact n m)
;;   A)
;;
;; となるので call/cc の戻り値がそのまま結果となることが分かります。
;; あとは call/cc で実際に実行される関数を再帰的に実行してその脱出に継続手続きを使っているわけだ。
;;
;; 最初見たときは意味が分からなかったけど分かった!
;; 今回新しかったのは
;;   set! せずにそのまま継続手続きを呼んでいる(手続き内に閉じている?)
;;   本質的には大域脱出?
;; あたりかな。
;;
;; 明日は自分で似たようなのを書いてみよう。