<< Previous exercise (4.12) | Index | Next exercise (4.14) >>
This isn't that elegant. The problem is that the way I wrote search-frame it returns the exact cons cell where the match occurred, so there really isn't any way to access the surrounding frame. Could easily be picked up by a garbage collector though.
(define (make-unbound! var env)
(let ((frame (first-frame env)))
(search-frame var
frame
(lambda (res) (and res (set-car! res '()) (set-cdr! res '())))
(lambda () '()))))
I believe 'make-unbound!' should construct a list for the evaluator to check with 'unbound?', and only afterwards it calls the unbinding procedure:
(define (make-unbound! var) (list 'unbound! var)) (define (unbound? exp) (tagged-list? exp 'unbound!)) (define (unbound!-var exp) (cadr exp)) (define (unbound! var env) (define (remove-binding var bindings) (cond ((null? bindings) '()) ((eq? var (caar bindings)) (cdr bindings)) (else (cons (car bindings) (remove-binding var (cdr bindings)))))) (let ((frame (first-frame env))) (set-cdr! frame (remove-binding var (frame-bindings frame)))))
Here's both options:
(define (make-unbound-in-frame! var frame) (define (scan bindings-before bindings-after) (cond ((null? bindings-after) bindings-before) ((eq? var (caar bindings-after)) (append bindings-before (cdr bindings-after))) (else (scan (append bindings-before (list (car bindings-after))) (cdr bindings-after))))) (set-cdr! frame (scan '() (cdr frame)))) (define (make-unbound-local! var env) (make-unbound-in-frame! (var (first-frame env)))) (define (make-unbound! var env) (if (eq? env the-empty-environment) 'done (begin (make-unbound-local! var env) (make-unbound! var (enclosing-environment env)))))
My frames are in format ('*frame* (var1 val1) (var2 val2) ...) (as in sicp-ex-4.11). I didn't find the loops I wrote for sicp-ex-4.12 useful, as my scan-frame could only do anything to the final segment of the frame-bindings starting with the variable it was looking for.
As for the question the book asked, I found myself strongly preferring to unbind variables globally, for the following reasons:
wing
mazj
wing's answer is more 4 times quick than my:
(define (make-unbound! var env) ;4*linear (let ((frame (first-frame env))) (define pairs (filter (lambda (pair) (not (eq? (car pair) var-target))) (map cons (car frame) (cdr frame)))) (set-car! frame (map car pairs)) (set-cdr! frame (map cdr pairs))))