2

环境不是计划延续的一部分吗?

我已经用 Chicken、Gauche、Racket 和 Gambit 对此进行了测试,它们的行为都相似:

(define kont #f)

(let ((a 1)
      (b 2))
  (call-with-current-continuation
   (lambda (k)
     (set! kont k)
     (display 'mutating)
     (newline)
     (set! a -1)
     (set! b -2)))
  (display (+ a b))
  (newline))

我希望在评估 LET 时为 -3,但在对 kont 的调用中为 +3(因为我认为程序会在突变之前记住 a 和 b 的绑定):

(let ... ) ; <-- evaluating the LET above
; prints "mutating"
=> -3
(kont 100)
=> -3
(kont 100)
=> -3

所以延续只影响控制,而不影响环境?在这种情况下,为什么说实现延续的方法之一是“复制堆栈”(绑定不在堆栈上?)

4

2 回答 2

3

延续捕获绑定。但是,正如您推测的那样,这些绑定是可变的。

在这里,您被“复制堆栈”的口号误导了。虽然这是考虑 call/cc 的合理方式,但这并不是故事的全部。一方面,你真的不想要一个语言特性暴露本地绑定是否是堆栈分配的。

相反, call/cc 是使用“程序上下文”的概念定义的。为了更好地处理这个问题,您可能想看看 Shriram Krishnamurthi 的(免费,在线)教科书PLAI,或(不是免费的,更深入的)书“Semantics Engineering with PLT Redex”。

作为旁白; 您的程序并没有真正检查您希望它检查的内容,因为您从未调用过捕获的延续。我想你想写这样的东西:

#lang racket

(define kont #f)

(let ([a 3])

  (let/cc k
    (set! kont k)
    (set! a 4))
  (printf "~s\n" a))

(kont)

...这显示了您上面提到的几乎相同的行为。

于 2011-05-14T15:00:26.650 回答
1

您可以使用 set! 更改环境中 a 和 b 的值。所以 a 和 b 在 continuation 环境中是 -1 和 -2。您无法展开副作用。在您的延续中,a、b 和 kont 之间没有区别。

于 2011-05-14T14:32:14.660 回答