题目:

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

画出上述定义与调用涉及到的环境结构。

解:

首先根据书中提到过的,let形式是lambda表达式的语法糖,可以将make-withdraw过程写成如下形式:

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

再者,过程定义也是lamdba的语法糖,所以make-withdraw过程可以进一步写成如下形式:

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

这一步的转换主要是为了方便理解。

接下来我们就可以画出求值上述定义所产生的环境结构:

              +-------------------------+
  全局环境+--> | make-withdraw:+-+       |
              |                 |       |
              +----------------------+--+
                                |    ^
                                |    |
                                |    |
                                v    +
                                参数:initial-amount
                                过程体:(lambda (balance)...initial-amount)

首先求值子表达式(lambda (initial-amount)...)),将产生一个过程对象: (1)此过程对象以initial-amount为参数,以被求值的lambda表达式的正文(lambda (balance)...initial-amount)为过程体。 (2)因为是在全局环境中求值,此过程对象环境指针指向全局环境。

然后通过define,在全局环境中建立make-withdraw与过程对象的约束。

本题的关键点在于理解定义W1所产生的环境结构:

              +-------------------------+
全局环境 +---> | make-withdraw:+-+       |
              | W1:             |       |
              +--+---------+---------+--+
                 |         ^    |    ^
                 |         |    |    |
                 |         |    v    +
                 |         |    参数:initial-amount
                 |         |    过程体:(lambda (balance)...initial-amount)
                 |         |
                 | +-------+------------+
                 | | initial-amount:100 | <--+ E1
                 | +-----------------+--+
                 |                   ^
                 |                   |
                 | +-----------------+-----+
                 | | balance:initial-amount| <--+ E2
                 | +-----------------+-----+
                 |                   ^
                 |                   |
                 |                   +
                 +-------------->参数:amount
                                 过程体:(if (>= balance amount)..."Insufficient funds!")

因为W1不接受参数,所以我们没必要将其define形式转换成lambda形式。首先求值子表达式(make-withdraw 100),将创建一个新的环境E1,它开始于一个框架,在这个框架里建立make-withdraw的形参initial-amount与实参100的约束,然后在环境E1的上下文中求值make-withdraw的过程体(注意,这里过程体是((lambda (var) (body)) exp)的形式,即将lamdba表达式应用到复合表达式的形式,所以求值这个过程体并不会创建一个新的过程对象!!!)。由于过程体仍然是一个复合表达式,所以继续创建一个新的环境E2,它开始于一个框架,在这个框架里建立lambda表达式的形参balance与实参initial-amount的约束,然后在环境E2的上下问中求值lambda表达式的正文(lambda(amount)...),由于正文是一个lambda表达式,所以将创建一个过程对象: (1)此过程对象以amount为参数,以被求值的lambda表达式的正文(if (>= balance amount)..."Insufficient funds!")为过程体。 (2)因为是在E2环境中求值,此过程对象环境指针指向E2环境。

然后通过define,在全局环境中建立W1与过程对象的约束。

下面继续求值(W1 50),创建的环境结构如下: