Exercise 3.11. In section 3.2.3 we saw how the environment model described the behavior of procedures with local state. Now we have seen how internal definitions work. A typical message-passing procedure contains both of these aspects. Consider the bank account procedure of section 3.1.1:
(define (make-account balance)
(define (withdraw amount)
(if (>= balance amount)
(begin (set! balance (- balance amount))
balance)
"Insufficient funds"))
(define (deposit amount)
(set! balance (+ balance amount))
balance)
(define (dispatch m)
(cond ((eq? m 'withdraw) withdraw)
((eq? m 'deposit) deposit)
(else (error "Unknown request -- MAKE-ACCOUNT"
m))))
dispatch)
Show the environment structure generated by the sequence of interactions
(define acc (make-account 50))
((acc 'deposit) 40)
90
((acc 'withdraw) 60)
30
Where is the local state for acc kept? Suppose we define another account
(define acc2 (make-account 100))
How are the local states for the two accounts kept distinct? Which parts of the environment structure are shared between acc and acc2?
首先是定义 make-account:
+-------------------------------+
| make-account: ---+ |
| | |
+------------------+------------+
|
|
|
|
|
v
Parameter: balance
body: (define (withdraw..))
(define (deposit..))
(define (dispatch..))
dispatch
然后是定义 acc,
+-------------------------------------------------------------+
| make-account: ... |
| acc ----+ |
+---------+---------------------------------------------------+
| ^
| |
| E1 |
| +----------+---------+
| | withdraw:... |
| +------------>| deposit:... |
| | | dispatch:... |
v | | balance: 50 |
Parameter: m +--------------------+
body: ...
运行 ((acc ‘deposit) 40)
+-------------------------------------------------------------+
| make-account: ... |
| acc ----+ |
+---------+---------------------------------------------------+
| ^
| |
| E1 |
| +----------+---------+
| | withdraw:... | (set! balance (+ balance amount))
| +------------>| deposit:... | <-----------------+
| | | dispatch:... | |
v | | balance: 50 (-->90)| |
Parameter: m +--------------------+ |
body: ... ^ E3 |
E2 | +-------+-----+
+------+-------+ | amount: 40 |
| m: 'deposit | +-------------+
+--------------+
(acc 'deposit)
得到结果 balance 将从 50 变为 90。
下一步是 ((acc 'withdraw) 60)
,它将首先绑定 dispatch 的 m,然后绑定 withdraw 的 amount 到 60,最后改变 balance
+-------------------------------------------------------------+
| make-account: ... |
| acc ----+ |
+---------+---------------------------------------------------+
| ^
| |
| E1 |
| +----------+---------+
| | withdraw:... | (begin (set! balance...))
| +------------>| deposit:... |<---------------+
| | | dispatch:... | |
v | | balance: 90(-->30) | |
Parameter: m +--------------------+ |
body: ... ^ |
E4 | |
+------+------+ E5 +------+---------+
| m:'with-draw| | amount: 60 |
+-------------+ +----------------+
可以看出 acc 的局部状态保存在 E1 中。当我们另外定义一个 (define acc2 (make-account 100)) 的时候,acc2 的环境将会创建一个 E6,这个 E6 将与 E1 的初始状态一样。 acc 与 acc2 共享的部分只会是代码,两者的环境是各自独立的。