next up previous contents
Next: Modeling with Mutable Data Up: The Environment Model of Previous: Frames as the Repository

Internal Definitions

Section [*] introduced the idea that procedures can have internal definitions, thus leading to a block structure as in the following procedure to compute square roots:

(define (sqrt x)
  (define (good-enough? guess)
    (< (abs (- (square guess) x)) 0.001))
  (define (improve guess)
    (average guess (/ x guess)))
  (define (sqrt-iter guess)
    (if (good-enough? guess)
        guess
        (sqrt-iter (improve guess))))
  (sqrt-iter 1.0))
Now we can use the environment model to see why these internal definitions behave as desired. Figure [*] shows the point in the evaluation of the expression (sqrt 2) where the internal procedure good-enough? has been called for the first time with guess equal to 1.


  \begin{figure}\par\figcaption {{\tt Sqrt} procedure with internal definitions.}\end{figure}

Observe the structure of the environment. Sqrt is a symbol in the global environment that is bound to a procedure object whose associated environment is the global environment. When sqrt was called, a new environment E1 was formed, subordinate to the global environment, in which the parameter x is bound to 2. The body of sqrt was then evaluated in E1. Since the first expression in the body of sqrt is

(define (good-enough? guess)
  (< (abs (- (square guess) x)) 0.001))
evaluating this expression defined the procedure good-enough? in the environment E1. To be more precise, the symbol good-enough? was added to the first frame of E1, bound to a procedure object whose associated environment is E1. Similarly, improve and sqrt-iter were defined as procedures in E1. For conciseness, figure [*] shows only the procedure object for good-enough?.

After the local procedures were defined, the expression (sqrt-iter 1.0) was evaluated, still in environment E1. So the procedure object bound to sqrt-iter in E1 was called with 1 as an argument. This created an environment E2 in which guess, the parameter of sqrt-iter, is bound to 1. Sqrt-iter in turn called good-enough? with the value of guess (from E2) as the argument for good-enough?. This set up another environment, E3, in which guess (the parameter of good-enough?) is bound to 1. Although sqrt-iter and good-enough? both have a parameter named guess, these are two distinct local variables located in different frames. Also, E2 and E3 both have E1 as their enclosing environment, because the sqrt-iter and good-enough? procedures both have E1 as their environment part. One consequence of this is that the symbol x that appears in the body of good-enough? will reference the binding of x that appears in E1, namely the value of x with which the original sqrt procedure was called.

The environment model thus explains the two key properties that make local procedure definitions a useful technique for modularizing programs:

Exercise. In section [*] 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 [*]:

(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?  


next up previous contents
Next: Modeling with Mutable Data Up: The Environment Model of Previous: Frames as the Repository
Ryan Bender
2000-04-17