函数两次调用时,let中定义的变量发生了变化

时间:2018-07-29 14:17:57

标签: scheme racket

考虑以下代码:

(define f2!
  (let([n 0])
    (lambda()
      (set! n (add1 n))
      n)))
(f2!)
(f2!)

我希望输出为1 1,因为每次我们调用f2!时,n将重新定义为0。

但是输出为:1 2。为什么会这样?

2 个答案:

答案 0 :(得分:2)

您已完成一个针对变量关闭的函数。简而言之,这是一个可怜的人。

调用f1!时,相同的自由绑定n(实例变量)将被突变并返回。您已经创建了一个计数器。

您可以使用多种语言进行相同的操作,因为它们中的大多数都是词汇性的。例如。 JS:

const fBang = (() => {
  let n = 0;
  return () => ++n;
})();

console.log(fBang()); // prints 1
console.log(fBang()); // prints 2

答案 1 :(得分:1)

let是所应用的lambda的语法糖,因此使用let的扩展形式可能更容易查看其原因:
(define f2! ((lambda (n) (lambda () (set! n (add1 n)) n)) 0)) 因此,当您定义f2!时,您应用 lambda(第二行),同时将其参数n绑定到方案对象0(第四行)。 f2!的定义是该应用程序的另一个lambda对象的结果。 该内部Lambda具有一个环境,其中包含第一个Lambda(即n)的参数。不是这些参数的副本,而是它们的实际引用,因此,当您应用内部lambda和set!的值n时,您将设置引用的n的值就像您首次定义f2!时所绑定的。

TL; DR,您一次定义了f2!,然后绑定了n,从那时起,您就获得并设置了相同的n