码迷,mamicode.com
首页 > 其他好文 > 详细

call/cc分析一例

时间:2014-10-19 21:15:46      阅读:199      评论:0      收藏:0      [点我收藏+]

标签:io   sp   on   cti   工作   ef   as   程序   return   

(define (fact n)
  (let ((r 1) (k ‘void))
    (call/cc (lambda (c) (set! k c))) 
    (set! r (* r n))
    (set! n (- n 1))
    (if (= n 1) r (k ‘recurse))))

(fact 5)

老师:为什么能工作?
学生:不知道!
老师:(call/cc (lambda (c) (set! k c))) 干了什么?
学生:call/cc 的全称是 call-with-current-continuation, 它调用一个单参数的函数,调用时把当前延续作为那个单参数函数的参数。 所以,上式就是把当前延续存入 k 中。
老师:当前延续是什么?
学生:(escaper (lambda (~) (~ (set! r (* r n)) (set! n (- n 1)) (if (= n 1) r (k ‘recurse)))))
老师:怎么存入 k ?
学生:(set! k (escaper (lambda (~) (~ (set! (* r n)) (set! n (- n 1)) (if (= n 1) r (k ‘recurse))))))
老师:(call/cc (lambda (c) (set! k c))) 和 (set! k (escaper (lambda (~) (~ (set! (* r n)) (set! n (- n 1)) (if (= n 1) r (k ‘recurse)))))) 等价吗,可以相互替换吗?
学生:可以!

(define (fact n)
  (let ((r 1) (k ‘void))
    (set! k 
          (escaper (lambda (~) (~ (set! (* r n)) (set! n (- n 1)) (if (= n 1) r (k ‘recurse)))))) ;; A
    (set! r (* r n)) (set! n (- n 1)) (if (= n 1) r (k ‘recurse))))                               ;; B

老师:为什么能工作?
学生:跟踪一下 (fact 5) 就知道了

B: n=5 => r=5,  n=4  [ n != 1,continue ]
A: n=4 => r=20, n=3  [ n != 1, continue ]
A: n=3 => r=60, n=2  [ n != 1, continue ]
A: n=2 => r=60, n=1  [ n == 1, return r and escape ]

老师:为什么是递归的?
学生:因为延续是一种函数,延续递归了,这个延续函数就递归了。

老师:这里的延续本质上还是递归。尽管延续被叫做有上下文的 goto,这个程序也可以看成用了 goto 的。

(define (fact n)
  (let ((r 1) (k ‘void))
    (call/cc (lambda (c) (set! k c)))
    (set! r (* r n))
    (set! n (- n 1))
    (if (= n 1)
        r
        (k ‘recurse) ;; => go back to (call/cc (lambda (c) (set! k c)))
        )))

学生:但这只是一种“比喻”,实质上它是递归!
老师:你说的对。

call/cc分析一例

标签:io   sp   on   cti   工作   ef   as   程序   return   

原文地址:http://www.cnblogs.com/billythekid/p/4035398.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!