1

我想了解如何没有call/cc.

我从这个小例子开始了解如何修改代码以便我可以在不使用它的情况下使用它call/cc

(define x 0)

( + 2 (call-with-current-continuation
  (lambda (cont)
    (set! x cont)
  3)))

(x 4)

当我使用它执行函数时,call/cc它给了我5,然后当我执行时6(x 4)

我使用此功能替换call/cc

(define (call/cc-cps f continuation)
   (f continuation continuation))

我试图将此功能更改为 CPS(连续传递样式):

(call/cc-cps
  (lambda (exit cont)
   (set! x cont)
   3)
(lambda (value)
  (+ value 2)))

但是当我执行它时,我得到3而不是5。但我确实得到了6个。(x 4)

你能告诉我有什么问题吗?谢谢你

4

1 回答 1

1

使用 CPS,您没有顶级延续提示,因此为了进行比较,您需要将代码放在一个空的 let 中,如下所示:

(let ()
  (define x 0)
  (+ 2 (call-with-current-continuation
         (lambda (cont)
           (set! x cont)
           3))) ; ==> 5
  (x 4))
  ; ==> 6
  ; ==> 6
  ; ==> 6
  ; ... forever 

这成为一个无限循环,因为您(x 4)每次都在求和之后调用。

;; CPS-version of +
(define (+& a b continuation)
  (continuation (+ a b)))

注意 &。它用于表示该函数需要一个额外的参数,即延续。在 CPS 中,您可以call/cc这样定义:

(define (call/cc& f& continuation)
  (define (exit& value actual-continuation)
    (continuation value))
  (f& exit& continuation))

请注意,它与您的版本完全不同。它将退出函数传递给f&而不是使用传递的函数来actual-continuation完成所有剩余的计算,而是将它传递给继续call/cc&

现在我们可以将你的程序改写成这样:

((lambda (x& halt-continuation) 
  (call/cc& (lambda (cont continuation)
              ((lambda (ingnored-undefined-value) (continuation 3))
               (set! x& cont)))
            (lambda (three)
              (+& 2 three (lambda (ignored-result)
                      (x& 4 halt-continuation))))))
 0 values)

ignored-result5第一次和无限次,它用4 ignored-resultis计算它6,就像在非 CPS 版本中一样let

我使用 DrRacket,它有一个非常好的调试器,你可以一步一步来看看到底发生了什么。我在通话中添加了一个断点+&并按下并|>看到可变three拳头是无限次。34

CPS 并不容易。call/cc为我们提供了 CPS 的好处,而不会使代码更难阅读。在没有协同程序的情况下实现call/cc对我来说是一个挑战,因为我一开始就很复杂call/cc,特别是如果你不小心就会出现无限循环。

于 2017-08-18T20:59:09.773 回答