1

我正在为我的计划决赛而学习,与当地国家的对象一直是一个艰难的主题。

这是我期末考试中的一个问题,我需要帮助。

(define (make-incrementer n)
  (let ((old 0)
        (new 0))
    (lambda ()
      (cond ((< new n) 
             (set! old new)
             (set! new (+ new 1))
             old)
            (else 
             (set! old 0)
             (set! new 1)
             old)))))

(define a (make-incrementer 3))
(define b (make-incrementer 3))
(define c a)

; 1) (a)
; 2) (a)

为什么a第二次调用时返回1?我正在查看代码,n我们给它的总是 3。那么它不是总是这样else吗?

4

2 回答 2

3

欢迎来到封闭的美妙世界!这是一个教科书式的例子,说明了 Scheme 中的闭包是如何工作的。

因此make-counter返回一个函数,该函数具有从其封闭环境中捕获的 3 个变量:n, old, new. 在这种情况下,启动环境看起来像

_name_|_value_
 n    | 3
 old  | 0
 new  | 1

在每次调用时,如果它们大于,它会递增old并环绕它们。因为它是 using ,所以这种递增会改变 lambda 环境中的变量,但是由于这些变量是从周围环境中捕获的,因此它们也会为所有未来的调用而改变。newnset!

这就是为什么即使使用相同的输入,您也会获得不同的回报。

如果这看起来像巫术,你可以把它想象成更常见语言中的对象:

例如 Python:

class Foo():
    def __init__(self, n, m):
        self.n = n
        self.m = m
    def count(self):
        self.n += 1
        if self.n == self.m:
           self.n = 1
        return self.n-1

f = Foo(0, 2)

f.count() # 1
f.count() # 0

这是相同的基本思想,只是在这里我们更明确地说明了环境的来源,self. 在 Scheme 中,我们通过 lambda 捕获周围变量来模拟这一点。

有关更多信息,请查看SICP

于 2013-05-14T02:25:32.527 回答
0

以下是一些示例,可能有助于捕获状态的概念:

(define (always x) 
  (lambda rest x))
(define always-true (always #t))
(always-true #f)
-> #t

(define (add-n n) 
  (lambda (m)
    (+ n m)))
(define add-1 (add-n 1))
(add-1 10)
-> 11

(define (complement predicate)
  (lambda (x)
    (not (predicate x)))
(define not-positive? (complement positive?))
(not-positive? -1)
-> #t

接下来是一个示例,其中捕获的状态(在这种情况下)发生了l突变。这类似于您的情况,其中newold被捕获和修改。

(define (nexting l)
  (lambda ()
    (if (null? l)
        '()
        (let ((answer (car l)))
          (set! l (cdr l))
          answer))))
(define next-user (nexting '(Alice Bob David)))
(next-user)
-> Alice
(next-user)
-> Bob
(next-user)
-> David
(next-user)
'()
于 2013-05-14T02:45:57.603 回答