以下两个案例对于存储的连续调用的i
值有不同的行为。如何解释差异?
>(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
答案 0 :(得分:0)
我在这里做出假设,如果我错了,请原谅我:)
我能够在Racket和我的宠物Scheme实现中重现这一点。问题可能隐藏在特定Scheme实现中实现continuation的方式中。 所以这是我的假设:
call/cc
时复制堆栈,副本包含已评估的过程参数。这意味着在
中(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/cc
和i
的位置,则会重新评估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