从 call/cc 返回延续
Returning continuations from call/cc
Matt Might 在 continuations by example 上的帖子中定义了辅助函数
(define (current-continuation)
(call/cc (lambda (cc) (cc cc))))
抓住并return当前的延续。为什么要用(cc cc)
来延续return?为什么不使用 cc
:
(define (current-continuation)
(call/cc (lambda (cc) cc)))
Might 的示例在 current-continuation
的任一版本中的工作方式相同。这只是风格问题,还是有更深层次的问题在起作用?
所以,记住 call/cc
在 CPS 中是这样的:
(define (call/cc& f k)
(f (lambda (v ignored-cont) (k v)) k))
所以第一个这样做:
(define (current-continuation k1)
(call/cc& (lambda (cc k2) (cc cc k2)) k1))
第二个这样做:
(define (current-continuation k1)
(call/cc& (lambda (cc k2) (k2 cc)) k1))
因为 call/cc
将传递 k1
作为 k2
而 cc
将使用 k1
两者最终都会做 (k1 cc)
。因此两者之间没有区别。
呃,好的。如果你能原谅我需要指望我的手指,定义
(define (current-continuation k1)
(call/cc& (lambda (cc k2) (k2 cc)) k1))
(define (call/cc& f k)
(f (lambda (v ignored-cont) (k v)) k))
转电话
(current-continuation after-cc-k)
进入
(call/cc& (lambda (cc k2) (k2 cc)) k1)
在形式参数绑定下
k1 = after-cc-k
重写为
(call/cc& (lambda (cc k2) (k2 cc)) after-cc-k)
定义为
(f (lambda (v ignored-cont) (k v)) k)
在形式参数绑定下
f = (lambda (cc k2) (k2 cc))
k = after-cc-k
重写为
((lambda (cc k2) (k2 cc)) (lambda (v ignored-cont) (after-cc-k v)) after-cc-k)
计算结果为
(k2 cc)
在形式参数绑定下
cc = (lambda (v ignored-cont) (k1 v))
k2 = after-cc-k
重写为
(after-cc-k (lambda (v ignored-cont) (after-cc-k v)))
即 return 调用 current-continuation
之后的剩余计算继续调用 current-continuation
.[=38= 之后的剩余计算]
现在定义
(define (current-continuation k1)
(call/cc& (lambda (cc k2) (cc cc k2)) k1))
导致调用
(current-continuation after-cc-k)
定义为
(call/cc& (lambda (cc k2) (cc cc k2)) k1)
在形式参数绑定下
k1 = after-cc-k
重写为
(call/cc& (lambda (cc k2) (cc cc k2)) after-cc-k)
定义为
(f (lambda (v ignored-cont) (k v)) k)
在形式参数绑定下
f = (lambda (cc k2) (cc cc k2))
k = after-cc-k
重写为
((lambda (cc k2) (cc cc k2)) (lambda (v ignored-cont) (after-cc-k v)) after-cc-k)
计算结果为
(cc cc k2)
在形式参数绑定下
cc = (lambda (v ignored-cont) (after-cc-k v))
k2 = after-cc-k
重写为
((lambda (v ignored-cont) (after-cc-k v))
(lambda (v ignored-cont) (after-cc-k v)) after-cc-k)
计算结果为
(after-cc-k v)
在形式参数绑定下
v = (lambda (v ignored-cont) (after-cc-k v))
ignored-cont = ...
重写为
(after-cc-k (lambda (v ignored-cont) (after-cc-k v)))
即,current-continuation
的另一个定义产生了相同的东西。呼。
示例中写的完全一样,没有区别。但是,如果需要,Might 提供的功能更强大,因为如果需要,可以更深入地嵌套带有延续的转义。也就是说,你可以这样写
(define (current-continuation)
(call/cc (lambda (cc) (+ 1234 (cc cc))))
(define (current-continuation)
(call/cc (lambda (cc) (printf "~v" (cc cc)))))
...或类似的东西,你仍然会得到相同的结果。基本上,作为一名经验丰富的延续程序员,我认为 "yes, I want to escape with the continuation value" 的想法是合理的。不过,您是对的,我相信您提供的两个定义在所有情况下都是等效的。不过,证明它需要一些思考。
Matt Might 在 continuations by example 上的帖子中定义了辅助函数
(define (current-continuation)
(call/cc (lambda (cc) (cc cc))))
抓住并return当前的延续。为什么要用(cc cc)
来延续return?为什么不使用 cc
:
(define (current-continuation)
(call/cc (lambda (cc) cc)))
Might 的示例在 current-continuation
的任一版本中的工作方式相同。这只是风格问题,还是有更深层次的问题在起作用?
所以,记住 call/cc
在 CPS 中是这样的:
(define (call/cc& f k)
(f (lambda (v ignored-cont) (k v)) k))
所以第一个这样做:
(define (current-continuation k1)
(call/cc& (lambda (cc k2) (cc cc k2)) k1))
第二个这样做:
(define (current-continuation k1)
(call/cc& (lambda (cc k2) (k2 cc)) k1))
因为 call/cc
将传递 k1
作为 k2
而 cc
将使用 k1
两者最终都会做 (k1 cc)
。因此两者之间没有区别。
呃,好的。如果你能原谅我需要指望我的手指,定义
(define (current-continuation k1)
(call/cc& (lambda (cc k2) (k2 cc)) k1))
(define (call/cc& f k)
(f (lambda (v ignored-cont) (k v)) k))
转电话
(current-continuation after-cc-k)
进入
(call/cc& (lambda (cc k2) (k2 cc)) k1)
在形式参数绑定下
k1 = after-cc-k
重写为
(call/cc& (lambda (cc k2) (k2 cc)) after-cc-k)
定义为
(f (lambda (v ignored-cont) (k v)) k)
在形式参数绑定下
f = (lambda (cc k2) (k2 cc))
k = after-cc-k
重写为
((lambda (cc k2) (k2 cc)) (lambda (v ignored-cont) (after-cc-k v)) after-cc-k)
计算结果为
(k2 cc)
在形式参数绑定下
cc = (lambda (v ignored-cont) (k1 v))
k2 = after-cc-k
重写为
(after-cc-k (lambda (v ignored-cont) (after-cc-k v)))
即 return 调用 current-continuation
之后的剩余计算继续调用 current-continuation
.[=38= 之后的剩余计算]
现在定义
(define (current-continuation k1)
(call/cc& (lambda (cc k2) (cc cc k2)) k1))
导致调用
(current-continuation after-cc-k)
定义为
(call/cc& (lambda (cc k2) (cc cc k2)) k1)
在形式参数绑定下
k1 = after-cc-k
重写为
(call/cc& (lambda (cc k2) (cc cc k2)) after-cc-k)
定义为
(f (lambda (v ignored-cont) (k v)) k)
在形式参数绑定下
f = (lambda (cc k2) (cc cc k2))
k = after-cc-k
重写为
((lambda (cc k2) (cc cc k2)) (lambda (v ignored-cont) (after-cc-k v)) after-cc-k)
计算结果为
(cc cc k2)
在形式参数绑定下
cc = (lambda (v ignored-cont) (after-cc-k v))
k2 = after-cc-k
重写为
((lambda (v ignored-cont) (after-cc-k v))
(lambda (v ignored-cont) (after-cc-k v)) after-cc-k)
计算结果为
(after-cc-k v)
在形式参数绑定下
v = (lambda (v ignored-cont) (after-cc-k v))
ignored-cont = ...
重写为
(after-cc-k (lambda (v ignored-cont) (after-cc-k v)))
即,current-continuation
的另一个定义产生了相同的东西。呼。
示例中写的完全一样,没有区别。但是,如果需要,Might 提供的功能更强大,因为如果需要,可以更深入地嵌套带有延续的转义。也就是说,你可以这样写
(define (current-continuation)
(call/cc (lambda (cc) (+ 1234 (cc cc))))
(define (current-continuation)
(call/cc (lambda (cc) (printf "~v" (cc cc)))))
...或类似的东西,你仍然会得到相同的结果。基本上,作为一名经验丰富的延续程序员,我认为 "yes, I want to escape with the continuation value" 的想法是合理的。不过,您是对的,我相信您提供的两个定义在所有情况下都是等效的。不过,证明它需要一些思考。