从 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 作为 k2cc 将使用 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" 的想法是合理的。不过,您是对的,我相信您提供的两个定义在所有情况下都是等效的。不过,证明它需要一些思考。