练习 3.10

练习给出的过程定义:

;;; 10-make-withdraw.scm

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

可以转换成以下 lambda 定义:

;;; 10-make-withdraw-using-lambda.scm

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

这个 lambda 版本的 make-withdraw 创建以下过程对象:

              +------------------------------------+
global env -> |                                    |
              |   make-withdraw --+                |
              +-------------------|----------------+
                                  |       ^
                                  |       |
                                  v       |
                                [*][*]----+
                                 |
                                 |
                                 v
                        parameters: initial-amount
                        body: ((lambda (balance)
                                   (lambda (amount)
                                       (if (>= balance amount)
                                           (begin (set! balance (- balance amount))
                                                  balance)
                                           "Insufficient funds")))
                               initial-amount)

如果执行表达式 (define w1 (make-withdraw 100)) ,我们得到以下环境:

              +------------------------------------+
global env -> |                                    |
              |                                    |
              +------------------------------------+
                     ^
(make-withdraw 100)  |
                     |
                 +--------------+
                 |              |
          E1 ->  | initial: 100 |
                 |              |
                 +--------------+

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

因为 make-withdraw 的函数体内又是一个函数调用,所以以上的求值又引发以下的求值发生。

首先是创建又一个过程对象:

              +------------------------------------+
global env -> |                                    |
              |                                    |
              +------------------------------------+
                     ^
(make-withdraw 100)  |
                     |
                 +--------------+
                 |              |
          E1 ->  | initial: 100 |
                 |              |
                 +--------------+
                   |        ^
                   |        |
                   |        |
               [*][*]-------+
                |
                |
                v
        parameters: balance
        body: (lambda (amount)
                  (if (>= balance amount)
                      (begin (set! balance (- balance amount))
                             balance)
                      "Insufficient funds"))

而这个新的过程对象会即刻被调用,继而产生又一个新环境:

              +------------------------------------+
global env -> |                                    |
              |                                    |
              +------------------------------------+
                     ^
(make-withdraw 100)  |
                     |
                 +--------------+
                 |              |
          E1 ->  | initial: 100 |
                 |              |
                 +--------------+
                              ^
((lambda (balance) ...) 100)  |
                              |
                        +--------------+
                        |              |
                 E2 ->  | balance: 100 |
                        |              |
                        +--------------+

                       (lambda (amount)
                           (if (>= balance amount)
                               (begin (set! balance (- balance amount))
                                      balance)
                               "Insufficient funds"))

(lambda (balance) ...) 的体内是另一个 lambda 表达式 (lambda (amount) ...) ,因此我们要为它创建又一个过程对象:

              +------------------------------------+
global env -> |                                    |
              |                                    |
              +------------------------------------+
                     ^
(make-withdraw 100)  |
                     |
                 +--------------+
                 |              |
          E1 ->  | initial: 100 |
                 |              |
                 +--------------+
                              ^
((lambda (balance) ...) 100)  |
                              |
                        +--------------+
                        |              |
                 E2 ->  | balance: 100 |
                        |              |
                        +--------------+
                           |        ^
                           |        |
                           v        |
                         [*][*]-----+
                          |
                          |
                          v
                   parameters: amount
                   body: (if (>= balance amount)
                             (begin (set! balance (- balance amount))
                                    balance)
                             "Insufficient funds")

(make-withdraw 100) 的求值过程到此就暂告一段落了,这时,可以将符号 w1 和所得的过程对象建立约束(bundle)了:

              +-------------------------------------------+
global env -> |                                           |
              |   w1                                      |
              +---|---------------------------------------+
                  |                               ^
                  |          (make-withdraw 100)  |
                  |                               |
                  |                    +--------------+
                  |                    |              |
                  |             E1 ->  | initial: 100 |
                  |                    |              |
                  |                    +--------------+
                  |                               ^
                  | ((lambda (balance) ...) 100)  |
                  |                               |
                  |                    +--------------+
                  |                    |              |
                  |             E2 ->  | balance: 100 |
                  |                    |              |
                  |                    +--------------+
                  |                      |        ^
                  |                      |        |
                  |                      v        |
                  +------------------> [*][*]-----+
                                        |
                                        |
                                        v
                                 parameters: amount
                                 body: (if (>= balance amount)
                                           (begin (set! balance (- balance amount))
                                           balance)
                                       "Insufficient funds")

使用之前求值得到的 w1 ,执行表达式 (w1 50) ,会创建以下环境:

              +-------------------------------------------+
global env -> |                                           |
              |   w1                                      |
              +---|---------------------------------------+
                  |                               ^
                  |          (make-withdraw 100)  |
                  |                               |
                  |                    +--------------+
                  |                    |              |
                  |             E1 ->  | initial: 100 |
                  |                    |              |
                  |                    +--------------+
                  |                               ^
                  | ((lambda (balance) ...) 100)  |
                  |                               |
                  |                    +--------------+
                  |                    |              |
                  |             E2 ->  | balance: 100 |
                  |                    |              |
                  |                    +--------------+
                  |                      |        ^  ^
                  |                      |        |  |                                    +------------+
                  |                      v        |  |                                    |            |
                  +------------------> [*][*]-----+  +------------------------------------| amount: 50 | <- E3
                                        |                                                 |            |
                                        |                                                 +------------+
                                        v
                                 parameters: amount                                    (if (>= balance amount)
                                 body: (if (>= balance amount)                             (begin (set! balance (- balance amount))
                                           (begin (set! balance (- balance amount))               balance)
                                           balance)                                        "Insufficient funds")
                                       "Insufficient funds")

环境 E3 在执行过程体中的表达式之后消失, E2balance 被设置为 50 ,以下是求值完毕之后的环境图:

              +-------------------------------------------+
global env -> |                                           |
              |   w1                                      |
              +---|---------------------------------------+
                  |                               ^
                  |          (make-withdraw 100)  |
                  |                               |
                  |                    +--------------+
                  |                    |              |
                  |             E1 ->  | initial: 100 |
                  |                    |              |
                  |                    +--------------+
                  |                               ^
                  | ((lambda (balance) ...) 100)  |
                  |                               |
                  |                    +--------------+
                  |                    |              |
                  |             E2 ->  | balance: 50  |
                  |                    |              |
                  |                    +--------------+
                  |                      |        ^
                  |                      |        |
                  |                      v        |
                  +------------------> [*][*]-----+
                                        |
                                        |
                                        v
                                 parameters: amount
                                 body: (if (>= balance amount)
                                           (begin (set! balance (- balance amount))
                                           balance)
                                       "Insufficient funds")

最后,定义另一个 make-withdraw 实例 w2 ,它的功能性和 w1 类似,但是却保存着自己的一簇状态变量和过程对象(最明显的就是它们各自的 balance 变量):

              +-----------------------------------------------------------------------------------------+
global env -> |                                                                                         |
              |   w1                                        w2                                          |
              +---|-----------------------------------------|-------------------------------------------+
                  |                               ^         |                               ^
                  |          (make-withdraw 100)  |         |                               |
                  |                               |         |                               |
                  |                    +--------------+     |                      +--------------+
                  |                    |              |     |                      |              |
                  |             E1 ->  | initial: 100 |     |               E1 ->  | initial: 100 |
                  |                    |              |     |                      |              |
                  |                    +--------------+     |                      +--------------+
                  |                               ^         |                               ^
                  | ((lambda (balance) ...) 100)  |         | ((lambda (balance) ...) 100)  |
                  |                               |         |                               |
                  |                    +--------------+     |                      +--------------+
                  |                    |              |     |                      |              |
                  |             E2 ->  | balance: 50  |     |               E2 ->  | balance: 100 |
                  |                    |              |     |                      |              |
                  |                    +--------------+     |                      +--------------+
                  |                      |        ^         |                          |       ^
                  |                      |        |         |                          |       |
                  |                      v        |         |                          v       |
                  +------------------> [*][*]-----+         +----------------------->[*][*]----+
                                        |                                             |
                                        |                                             |
                                        v                                             v
                         parameters: amount                             parameters: amount
                         body: (if (>= balance amount)                  body: (if (>= balance amount)
                                   (begin (set! balance                           (begin (set! balance
                                                (- balance amount))                      (- balance amount))
                                          balance)                                balance)
                                   "Insufficient funds")                          "Insufficient funds")

讨论

blog comments powered by Disqus