(define c
(let ((d 10))
(set! d (- d 2))
d))
(define c1
(let ((d 10))
(lambda (p)
(set! d (- d p))
d)))
现在c c
的输出为8 8
。
但是对于(c1 2) (c1 2)
,输出为8 6
。为什么会这样?
我认为我需要深入了解如何实际评估函数调用。
根据我的说法,对于第一个调用,评估应为(在第二种情况下)为函数c1创建一个本地环境,其中d的值为10,然后正常进行过程评估。然后,此调用结束后,整个环境将被破坏,第二个调用将发生相同的整个过程(如上所述)。因此第二个输出值也应该是8。但是它是6,为什么会这样?
答案 0 :(得分:1)
您在想吗?
(define c1
(let ((d 10))
(lambda (p)
(set! d (- d p))
d)))
它与以下内容完全相同:
(define c1
(lambda (p)
(let ((d 10))
(set! d (- d p))
d)))
不是。首先,变量d
是在lambda之前创建的,因此对于c1
的每次调用,它都是相同的自由变量。因此,更改d
会更改下一个呼叫。
第二个在调用时创建d
,并在调用完成后销毁。
在第一个Scheme中评估let形式。它创建d
,然后计算lambda,以便d
成为其闭包中的自由变量,并返回。然后,define语法使用产生的闭包值创建全局变量c1
。 let
超出范围,但是d
不会被垃圾回收,因为它仍然被一个值(闭包)引用。
答案 1 :(得分:0)
let
可以重写为lambda
抽象的直接应用
(mylet ([var rhs] ...) body ...) => ((lambda (var ...) body ...) rhs ...)
对c
的{{1}}进行脱糖
let
这只是(define c ((lambda (d) (set! d (- d 2)) d) 10))
在函数(我们称为10
)上的应用
f
对于(define f (lambda (d) (set! d (- d 2)) d))
(define c
(f 10))
c
c
,我们嵌套了lambdas
c1
(define f1 (lambda (d) (lambda (p) (set! d (- d p)) d)))
((f1 10) 2)
((f1 10) 2)
和8
。 (您期望的是什么)。但是,实际上,发生的是
8
返回(define c1
(f1 10))
(c1 2)
(c1 2)
和8
d被记忆 (here是斐波那契的示例,它使用与记忆过程和6
相同的包装)。
此外,对于set!
,您不能进行幼稚的替换。球拍的evaluation model说明了“如何为每个应用程序中的每个变量创建一个新位置”:
对由于可以更改与参数变量x相关联的值, 该过程首次执行时,该值不能替代x 已应用。
set!
的 tl; dr 评估会产生一个lambda,该lambda在即将进行的替换(环境)时关闭。然后在每次调用时由c1
对其进行突变。