継続渡しによる階乗計算をトレースしてみる

僕のカニみそ級の脳みそでは、無名関数が混じっていると混乱してしまうっぽいので、適当に名前を付けながらトレースしてみました。

(define fact/cps 
  (lambda (n cont)
    (cond
     ((= n 0) (cont 1))
     (else (fact/cps (- n 1) (lambda (m) (cont (* m n))))))))

(define cont (lambda (a) a))

のとき

(fact/cps 3 cont)

の評価過程を見ていきたいと思います。

(fact/cps 3 cont)
	-> (fact/cps 2 cont3)
		-> (fact/cps 1 cont2)
			-> (fact/cps 0 cont1)	;; 再帰境界条件
			-> (cont1 1)
		-> (cont2 (* 1 1))
		-> (cont2 1)
	-> (cont3 (* 2 1))
	-> (cont3 2)
  • > (cont (* 3 2))
  • > (cont 6)
  • > 6

...っと、こんな感じでしょうか。
ただし、cont3とcont2とcont1は

(define cont3 (lambda (v3) (cont (* 3 v3))))
(define cont2 (lambda (v2) (cont3 (* 2 v2))))
(define cont1 (lambda (v1) (cont2 (* 1 v1))))

となる関数です。

名前をつけたら混乱せずにたどれました。
ということで動きは理解できましたよ。