在第二种情况下无法理解输出

时间:2019-04-01 17:59:19

标签: racket

(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,为什么会这样?

2 个答案:

答案 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语法使用产生的闭包值创建全局变量c1let超出范围,但是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对其进行突变。