4.11 Exercise 4.11
One of the reasons that the approach using separate lists for
variables and values in the environment worked so nicely is
that a natural representation containing pointers to these
lists fell out of it. If we imagine the bindings instead as
a single list of binding pairs (where the value can itself
also be a list), our data representation seems more elegant,
but we lose that level of indirection that made the mutations
easy to write. To deal with this, we can instead define a
frame as having a head element in front, such that the
cdr of this frame is a reliable pointer to the list
of bindings.
| (define the-empty-environment-2 '(head)) |
| (define (lookup-variable-value-2 var env) | | (define (env-loop env) | | (define (scan bindings) | | (cond ((null? bindings) (env-loop (enclosing-environment env))) | | ((eq? var (caar bindings)) (cdar bindings)) | | (else (scan (cdr bindings))))) | | (if (eq? env the-empty-environment-2) | | (error "Unbound variable" var) | | (let ((frame (first-frame env))) | | (scan (cdr frame))))) | | (env-loop env)) |
|
| (define (extend-environment-2 bindings base-env) | | (cons (cons 'head bindings) base-env)) |
|
| (define (add-binding-to-frame-2! var val frame) | | (if (null? (cdr frame)) | | (set-cdr! frame (cons var val)) | | (begin | | (set-cdr! (cdr frame) (cons (cadr frame) (cddr frame))) | | (set-car! (cdr frame) (cons var val))))) |
|
| (define (define-variable-2! var val env) | | (let ((frame (first-frame env))) | | (define (scan bindings) | | (cond ((null? bindings) | | (add-binding-to-frame-2! var val frame)) | | ((eq? var (caar bindings)) | | (set-car! (car bindings) val)) | | (else (scan (cdr bindings))))) | | (scan (cdr frame)))) |
|
| (define (set-variable-2! var val env) | | (define (env-loop env) | | (define (scan bindings) | | (cond ((null? bindings) | | (env-loop (enclosing-environment env))) | | ((eq? var (caar bindings)) | | (set-cdr! (car bindings) val)) | | (else (scan (cdr bindings))))) | | (if (eq? env the-empty-environment-2) | | (error "Unbound variable -- SET!" var) | | (let ((frame (first-frame env))) | | (scan (cdr frame))))) | | (env-loop env)) |
|