<< Previous exercise (4.16) | Index | Next exercise (4.18) >>
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.
meteorgan