【问题标题】:Returning continuations from call/cc从 call/cc 返回延续
【发布时间】:2019-12-30 23:41:13
【问题描述】:

Matt Might 在continuations by example 上的帖子中定义了辅助函数

(define (current-continuation)
  (call/cc (lambda (cc) (cc cc))))

抓取并返回当前的延续。为什么使用(cc cc) 来返回延续?为什么不用cc

(define (current-continuation)
  (call/cc (lambda (cc) cc)))

Might 的示例与current-continuation 的任一版本的工作方式相同。这只是风格问题,还是有更深层次的问题在起作用?

【问题讨论】:

    标签: scheme continuations


    【解决方案1】:

    在示例中完全按照所写,没有区别。然而,从某种意义上说,Might 提供的更健壮,如果需要,可以更深地嵌套延续的转义。也就是说,你可以写类似

    (define (current-continuation)
      (call/cc (lambda (cc) (+ 1234 (cc cc))))
    
    (define (current-continuation)
      (call/cc (lambda (cc) (printf "~v" (cc cc)))))
    

    ... 或类似的东西,你仍然会得到相同的结果。基本上,我认为作为一个有经验的延续程序员,“是的,我想用延续值逃避”是合理的。不过,您是对的,我相信您提供的两个定义在所有情况下都是等效的。不过,证明它需要一些思考。

    【讨论】:

      【解决方案2】:

      嗯,好的。如果你能原谅我需要指望我的手指,定义

      (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)))
      

      也就是说,在调用current-continuation之后返回到剩余的计算,在调用current-continuation之后继续剩余的计算。

      现在定义

      (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 的其他定义相同。呼。

      【讨论】:

      • 为漂亮的细节投票?
      【解决方案3】:

      所以,请记住 CPS 中的 call/cc 是这样的:

      (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)。因此两者没有区别。

      【讨论】:

        猜你喜欢
        • 2011-02-16
        • 2016-01-18
        • 2017-01-22
        • 2019-12-17
        • 2016-06-05
        • 1970-01-01
        • 2011-08-25
        • 1970-01-01
        相关资源
        最近更新 更多