sicp-ex-4.17



<< Previous exercise (4.16) | Index | Next exercise (4.18) >>


meteorgan

  
  
  
 ;; a 
 because let expression will be substituted as lambda expression, every lambda expression will extend the environment. 
  
 ;; b 
 the new environment is confined to the let expression, it doesn't change the outer environment. 
  
 ;; c 
 Do away with the let - All the (define var '*unassigned*) which was there in the let statements should instead be moved on top of the body. The set! statements should simply replace the earlier defines. 
  
 Note that you cannot simply, move all defines to the start of the body, because that might allow the body to access variables not yet defined in the original code. 

pvk

Sequential definition:

 ((lambda <vars> 
     (define u <e1>) 
     (define v <e2>) 
     <e3>) <inputs>) 

will evaluate <e3> in the environment:

GLOBAL
------

FRAME1 (<e3> evaluated here)
------
<vars>: <inputs>
u: <e1>
v: <e2>

(where each frame is a child of the one above it.)

Simultaneous definition:

 ((lambda <vars> (let ((u '*unassigned*) 
                       (v '*unassigned*)) 
                    (set! u <e1>) 
                    (set! v <e2>) 
                    <e3>)) <inputs>) 

expands to

 ((lambda <vars> (lambda (u v) 
                    (set! u <e1>) 
                    (set! v <e2>) 
                    <e3>) 
                  '*unassigned* '*unassigned*) 
                  <inputs>) 

and since there are two lambdas, there are two frames:

GLOBAL
------

FRAME1
------
<vars>: <inputs>

FRAME2 (<e3> evaluated here)
------
u: <e1>
v: <e2>

It's pretty clear that evaluating an expression in either environment will give the same values for all variables, and thus the same result.

In addition to @meteorgan's idea of replacing (let ((u '*unassigned*) (v '*unassigned)) ...) with (define u '*unassigned*) (define v '*unassigned) ..., one can imagine a solution that would essentially translate the whole expression to

 ((lambda (<vars> u v) 
     (set! u <e1>) 
     (set! v <e2>) 
     <e3>) 
  <inputs> '*unassigned* '*unassigned*) 

Doing this would require modifying how procedures are applied to inputs, i.e., replace

 (eval-sequence (procedure-body procedure) 
                (extend-environment (procedure-parameters procedure) 
                                    arguments 
                                    (procedure-environment procedure))) 

in the definition of apply with

(eval-sequence (procedure-body procedure)
               (extend-environment (append (procedure-parameters procedure)
                                           (internally-defined-vars procedure))
                                   (append arguments (unassigneds procedure))
                                   (procedure-environment procedure)))

with appropriate definitions of the undefined terms, and modifications to the internal representation of procedures. I think this is all pretty academic, so excuse me if I leave out the details.