了解具有本地状态的对象 - Scheme

时间:2013-05-14 02:19:06

标签: lisp scheme mit-scheme

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

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

(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情况吗?

2 个答案:

答案 0 :(得分:3)

欢迎来到封闭的精彩世界!这是关于Scheme中闭包如何工作的教科书示例。

因此make-counter会返回一个函数,该函数包含3个从其封闭环境中捕获的变量:noldnew。在这种情况下,起始环境类似于

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

在每次调用时,如果它们大于old,它会递增newn并将它们包裹起来。因为它正在使用set!,所以这种递增会改变lambda环境中的变量,但由于这些变量是从周围环境中捕获的,因此它们也会在以后的所有调用中进行更改。

即使使用相同的输入,这也是您获得不同回报的原因。

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

例如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

答案 1 :(得分: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)
'()