SICP問題4.12

set-variable-value!, define-variable!およびlookup-variable-valueから共通パターンを取り込んだ抽象の定義。
define-variable!と次の問題まで含めて考えて、手続きを渡せるようにしておく。

(define (scan var vars vals proc)
  (cond ((null? vars) #f)
        ((eq? var (car vars)) (proc vars vals))
        (else (scan var (cdr vars) (cdr vals) proc))))

(define (scan-env-loop var env proc)
  (if (eq? env the-empty-environment)
      #f
      (let ((frame (first-frame env)))
        (let ((bind-pair 
               (scan var (frame-variables frame) (frame-values frame) proc)))
          (if (not bind-pair)
              (scan-env-loop var (enclosing-environment env) proc)
              bind-pair)))))

上の抽象を使って再定義した手続き

(define (lookup-variable-value var env)
  (let ((val (scan-env-loop var env
                            (lambda (vars vals) (car vals)))))
    (if (not val)
        (error "Unbound variable" var)
        val)))
(define (set-variable-value! var val env)
  (let ((val (scan-env-loop var env
                            (lambda (vars vals) (set-car! vals val) #t))))
    (if (not val)
        (error "Unbound variable -- SET!" var)
        val)))
(define (define-variable! var val env)
  (let ((frame (first-frame env)))
    (let ((result (scan var
                        (frame-variables frame)
                        (frame-values frame)
                        (lambda (vars vals) (set-car! vals val) #t))))
      (if (not result)
          (add-binding-to-frame! var val frame)))))