【问题标题】:How do closures in Scheme work?Scheme 中的闭包是如何工作的?
【发布时间】:2011-04-09 22:20:53
【问题描述】:

我在 Racket/DrScheme 中测试了以下代码:

(define (makem)
    (define x 34)
    (list (lambda () (set! x (+ x 1)) x)
          (lambda () (set! x (+ x 1)) x))
)

(define f (car (makem)))
(define f2 (car (cdr (makem))))

> (f)
35
> (f2)
35            ; I thought this would give me 36
> (f)
36
> (f)
37
>

在函数调用中创建的每个 lambda 是否都会获得其范围内每个变量的副本?是不是像某种隐式的让?我希望 lambda 有某种指向它们创建的范围的指针,使它们能够访问堆栈变量,但这告诉我不然,因为 f 和 f2 似乎有不同的 x 副本。究竟会发生什么?

【问题讨论】:

  • 你应该真的去阅读chapter 3 of SICP.我一直很困惑,直到我读到它,然后它让整个过程变得非常清楚。请特别参阅第 3.2.3 节,“作为本地状态存储库的框架”。 (简短的回答:是的,它有点像隐含的let,它们有不同的x 副本。)
  • 同样在 SICP 中,看看 applicative-order 与 normal-order。这将解释为什么列表中的两个函数都将 x 设置为 35。
  • @mquander:他们只有x 的不同副本,因为它们来自(makem) 的不同副本。如果它们实际上是对 (makem) 的一次调用的两个元素,而不是一次调用的第一个元素和另一个调用的第二个元素,那么它们将具有 x 的相同副本。
  • @dfan:是的,没错。

标签: lambda scope scheme closures


【解决方案1】:

您调用了两次(makem),因此您使用x 的两个不同副本创建了两个不同的环境。如果你调用了一次(makem),像这样:

(define m (makem))
(define f (car m))
(define f2 (car (cdr m)))

那么ff2 确实会共享同一个x,也就是m 中的那个。

【讨论】:

  • 天啊!现在它达到了我的预期。对事物进行两次评估时必须小心。在开始使用 lisp 之前,我就已经知道,这是一个愚蠢的错误!
猜你喜欢
  • 2018-09-13
  • 1970-01-01
  • 2013-06-07
  • 2012-09-08
  • 2020-01-06
  • 2017-07-04
  • 1970-01-01
  • 2017-08-18
  • 2010-09-19
相关资源
最近更新 更多