SICP 全笔记

Exercise 3.10. In the make-withdraw procedure, the local variable balance is created as a parameter of make-withdraw. We could also create the local state variable explicitly, using let, as follows:

(define (make-withdraw initial-amount)
  (let ((balance initial-amount))
    (lambda (amount)
      (if (>= balance amount)
          (begin (set! balance (- balance amount))
                 balance)
          "Insufficient funds"))))

Recall from section 1.3.2 that let is simply syntactic sugar for a procedure call:

(let ((<var> <exp>)) <body>)

is interpreted as an alternate syntax for

((lambda (<var>) <body>) <exp>)

Use the environment model to analyze this alternate version of make-withdraw, drawing figures like the ones above to illustrate the interactions

(define W1 (make-withdraw 100))

(W1 50)

(define W2 (make-withdraw 100))

Show that the two versions of make-withdraw create objects with the same behavior. How do the environment structures differ for the two versions?

首先是 make-withdraw

+------------------------------+
| make-withdraw: ----+         |
|                    |         |
+--------------------+---------+
                     |
                     |
                     |
                     |
                     |
             Parameter: initial-amount
                  body: (let ((balance initial-amount))
                          (lambda (amount)...))

在调用 (define W1 (make-withdraw 100)) 时的环境图

+-------------------------------------------------+
| make-withdraw: ...                              |
| W1 ----+                                        |
+--------+----------------------------------------+
         |                     ^
         |                     |
         |        E1           |
         |           +---------+----------+
         |  +------> |initial-amount:100  |
         |  |        |balance: 100        |
         v  |        +--------------------+
Parameter: amount
     body: ...

调用 (W1 50) 时

+-------------------------------------------------+
| make-withdraw: ...                              |
| W1 ----+                                        |
+--------+----------------------------------------+
         |                     ^
         |                     |
         |        E1           |
         |           +---------+----------+
         |  +------> |initial-amount:100  |
         |  |        |balance: 100        | <------------+
         v  |        +--------------------+              |
Parameter: amount                                        |    E2
     body: ...                                   +-------+-------+
                                                 | amount: 50    |
                                                 |               |
                                                 +---------------+
                                                    (if (>= balance amount)
                                                        (begin (set! balance (- balance amount))
                                                               balance)
                                                        "Insufficient funds")

在 E2 环境中运行代码时,balance 在 E2 中找不到,所以到 E2 的上一个 frame 中找,得到结构是 balance 为 100,于是运行 set! 得到结果

+-------------------------------------------------+
| make-withdraw: ...                              |
| W1 ----+                                        |
+--------+----------------------------------------+
         |                     ^
         |                     |
         |        E2           |
         |           +---------+----------+
         |  +------> |initial-amount:100  |
         |  |        |balance: 50         |
         v  |        +--------------------+
Parameter: amount
     body: ...

运行 (define W2 (make-withdraw 100)) 时,会构造一个新的环境 E3,与之前的 E1,E2 都没有关系。

+-------------------------------------------------+
| make-withdraw: ...                              |
| W1: ...                                         |
| W2:----+                                        |
+--------+----------------------------------------+
         |                     ^
         |                     |
         |        E3           |
         |           +---------+----------+
         |  +------> |initial-amount:100  |
         |  |        |balance: 100        |
         v  |        +--------------------+
Parameter: amount
     body: ...