0

我从第 2.9 节中读到了这样一个make-counter例子。方案编程作业

> (define make-counter
    (lambda ()
      (let ([next 0])
        (lambda ()
          (let ([v next])
            (set! next (+ next 1))
            v)))))
> (define count1 (make-counter))
> (count1)
0
> (count1)
1

我在这里很困惑,“下一步”的状态是如何保持的?

以我的理解,
(define count1 (make-counter))返回值v,然后是make-counter消失和销毁的过程,

count1再次被调用时,又被调用了一次make-counter,所以预期的结果应该一直是“0”。

但是,它神奇地打印以下内容:

> (count1)
1
> (count1)
2
> (count1)
3
> (count1)
4
> (count1)
5

如何保持“下一个”的状态?

4

2 回答 2

1

就是闭包的概念,它是一对指向环境的指针和指向代码的指针。代码中的变量指向闭包的环境。每次调用 yielder 时,代码都会访问闭包的环境并对其进行更新。

你可以这样做更简单:

(define make-counter
  (lambda(k)    ;; closure encloses the global env. containing `+`, `-`, `set!`, etc.
    (lambda()   ;; internal closure encloses an environment containing k
      (set! k (+ 1 k))  ;; each call of (counter) mutates `k`
      (- k 1))))
(define counter (make-counter 0))
(counter)
0
(counter)
1
(counter)
2
于 2020-04-07T13:12:34.993 回答
0

count1再次被调用时,又被调用了一次make-counter,所以预期的结果应该一直是“0”。

不,make-counter不会再次调用。再次调用的是最里面的 lambda,因为(make-counter)返回了最里面的 lambda。

为了更清楚地看到这一点,请像这样重写make-counter

(define (make-counter)
  (let ([next 0])
    (lambda ()  ; <- This lambda is the return value of `(make-counter)`.
      (let ([v next])
        (set! next (+ next 1))
        v))))

要更清楚地看到它,请摆脱make-counter

> (define count1 (let ([next 0])
                   (lambda ()
                     (let ([v next])
                       (set! next (+ next 1))
                       v))))
> (count1)
0
> (count1)
1

每次执行时(count1),您都在执行 lambda 的主体。

即使你(count1)一遍又一遍地调用,next也不会变成0,因为(count1)只会执行 lambda 的主体。next仅设置为最初定义的时间0count1

于 2020-03-28T07:16:26.213 回答