解释continuation中引用的变量的不同行为?

时间:2014-11-18 15:19:02

标签: scheme continuations

以下两个案例对于存储的连续调用的i值有不同的行为。如何解释差异?

案例A

>(define cc #f)
>(define (x)
    (let ((i 0))
    (set! i (+ i 100))
    (+ i (+ i (call/cc (lambda (k) (set! cc k) 1)))) ; call/cc is not included by set!
    (set! i (+ i 10))
    i))
> (x)
110
> (cc 50) ; the context variable i changes as cc calling
120
> (cc 50)
130
<案例B
> (define cc #f)
> (define (x)
    (let ((i 0))
    (set! i (+ i 100))
    (set! i (+ i (call/cc (lambda (k) (set! cc k) 1)))) ; call/cc is included by set!
    (set! i (+ i 10))
    i))
> (x)
111
> (cc 50) ; the context variable i always be 0, not changing as cc calling
160
> (cc 50)
160        

1 个答案:

答案 0 :(得分:0)

我在这里做出假设,如果我错了,请原谅我:)

我能够在Racket和我的宠物Scheme实现中重现这一点。问题可能隐藏在特定Scheme实现中实现continuation的方式中。 所以这是我的假设:

  • 实现从左到右评估过程的参数。
  • 结果值存储在堆栈中。
  • 调用call/cc时复制堆栈,副本包含已评估的过程参数。
  • 当调用continuation时,复制的堆栈将与评估的过程参数一起恢复。

这意味着在

(set! i (+ i (call/cc (lambda (k) (set! cc k) 1))))
i应用程序中的

+call/cc之前进行评估,其值100存储在堆栈中。调用cc时,它不会重新评估i,而是使用之前评估过的值100。因此,在致电(cc 50)时,您将获得

(set! i (+ 100 50))

如果您切换call/cci的位置,则会重新评估i,从而获得正确的结果。

(define cc #f)
(define (x)
    (let ((i 0))
    (set! i (+ i 100))
    (set! i (+ (call/cc (lambda (k) (set! cc k) 1)) i))
    (set! i (+ i 10))
    i))
> (x)
111
> (cc 50)
171
> (cc 50)
231