6.001 Problem Set 5 SolutionsFall 1990		1


MASSACHUSETTS INSTITUTE OF TECHNOLOGY
Department of Electrical Engineering and Computer Science
6.001Structure and Interpretation of Computer Programs
Spring Semester, 1990

Problem Set 5Solutions

Tutorial Problem 1: (Exercise 3.11 on page 198 of the textbook.)

Make-account is a procedure defined in the global environment.  Calling make-account with 
an argument of 50 produces an environment in which balance (the parameter of make-
account) is bound to 50.  When the body of make-account get executed in this 
environment, local procedures withdraw, deposit, and dispatch are defined in this 
environment, and the dispatch procedure is returned as the value that is bound to acc.

Now evaluating ((acc 'deposit) 40) first calls the acc procedure with the symbol 
deposit as argument.  This builds an environment in which m (the parameter of acc) is 
bound to the symbol deposit.  Evaluating the body of acc (the cond clause) returns the 
local dispatch procedure, and this is the procedure that is called with 40 as argument.  This 
call builds an environment in which amount is bound to 40.  Note that this environment 
contains the original binding of balance, which is what is changed by the set! instruction.

                                         


Evaluating ((acc 'withdraw) 60) once again calls the acc object, and following that, the 
local withdraw procedure.  Notice that the frames for these calls are new framesin the 
environment model, a new frame is created every time a procedure is called.

                                         

Finally, defining acc2 with a new call to make-account, builds a new environment, with its 
own binding to balance and its own local deposit, withdraw, and dispatch procedures; and 
with dispatch bound to acc2.

The frames with the bindings to balance hold the local state for the two account 
procedureseach one has its own balance   The only part of the environment shared by acc 
and acc2 is the global environment.

                                            

Tutorial Problem 2:  One way to define the procedure flip is simply to use a global variable,
count, that flips between 1 and 0 by being set to 1count:

(define count 1)

(define (flip)
  (set! count (- 1 count))
  count)

However, this makes count a global variable.  We couldn't have two flip procedures that 
behave independently; and someone changing the value of count would mess up the flip 
procedure.  One way to encapsulate count within the flip procedure is to use a make-flip 
procedure, which generates flips, just like make-account generates bank accounts:

(define (make-flip)
  (let ((count 1))
    (lambda ()
      (set! count (- 1 count))
      count)))

(define flip (make-flip))


Alternatively, we can make a single flip, by using let to set up a local binding for count, 
and creating the procedure inside this environment:


(define flip
  (let ((count 1))
    (lambda ()
      (set! count (- 1 count))
      count)))

Note that, although the procedure (lambda) is create in the local environment, the define is 
performed in the global environment.

Problem 3:  Every-nth is similar make-count (above), except that  the count variable 
cycles 1, 2, ..., n., 1, 2, ...

(define (every-nth n)
  (let ((count 1))
    (lambda ()
      (set! count
            (if (= count n)
                1
                (+ count 1)))
      (if (= count n) 1 0))))
     
(define every-2nd (every-nth 2))
                

Problem 4:  This is exactly the situation of the third definition of flip shown in problem 
2 above:

(define f
   (let ((x 5))
     (lambda (...) ...)))


Problem 5:What  we want is to have a local environment with count in it, and two procedures 
whose environment pointers point to this environment.  We also want these two procedures bound 
in the global environment by the names c and reset:

                                      

One way to accomplish this is to first make bindings for c and reset  in  global 
environment. (It doesn't matter what they are bound to.)  Then create a local environment 
(by means of let) and set! c and reset to procedures that are created in this local 
environment:

(define c '())
(define reset '())

(let ((count -1)) ;initialize count to -1 since we
                  ;increment it before returning it
  (set! c
        (lambda ()
          (set! count (+ count 1))
          count))
  (set! reset
        (lambda ()
          (set! count -1)
          'ok)))

Another way is to use a maker procedure that returns a pair of local procedures (using 
cons) and then select c and reset as the car and cdr of this pair:

(define (make-count-reset-pair)
  (let ((count -1))
    (cons (lambda ()
            (set! count (+ count 1))
            count)
          (lambda ()
            (set! count -1)
            'ok))))

(define p (make-count-reset-pair))

(define c (car p))

(define reset (cdr p))

