SICP問題4.16

a. 値が*unassigned*ならエラーとするlookup-variable-value

(define (lookup-variable-value var env)
  (define (env-loop env)
    (define (scan vars vals)
      (cond ((null? vars)
             (env-loop (enclosing-environment env)))
            ((eq? var (car vars))
             (if (eq? (car vals) '*unassigned*)
                 (error "Unassigned variable" var)
                 (car vals)))
            (else (scan (cdr vars) (cdr vals)))))
    (if (eq? env the-empty-environment)
        (error "Unbound variable" var)
        (let ((frame (first-frame env)))
          (scan (frame-variables frame)
                (frame-values frame)))))
  (env-loop env))

b. 手続き本体を取り、以下の要領で変換を行う scan-out-defines
変換方法

(lambda <vars>
  (define u <e1>)
  (define v <e2>)
  <e3>)
;; 以下に変換
(lambda <vars>
  (let ((u '*unassigned*)
        (v '*unassigned*))
    (set! u <e1>)
    (set! v <e2>)
    <e3>))

scan-definesの定義。make-assignment手続きも追加する

(define (make-assignment var val)
  (list 'set! var val))

(define (scan-defines proc-body)
  (define (definitions rest result)
    (if (null? rest)
        result
        (let ((exp (car rest)))
          (if (definition? exp)
              (definitions (cdr rest)
                           (append result
                                   (list (list (definition-variable exp)
                                               (definition-value exp)))))
              (definitions (cdr rest) result)))))
  (define (body-exps rest result)
    (if (null? rest)
        result
        (let ((exp (car rest)))
          (if (definition? exp)
              (body-exps (cdr rest) result)
              (body-exps (cdr rest) (append result (list exp)))))))
  (define (make-let-list var-val-list)
    (map (lambda (x) (list (car x) ''*unassigned*)) var-val-list))
  (define (make-assignment-list var-val-list)
    (map (lambda (x) (make-assignment (car x) (cadr x))) var-val-list))
  (define (make-let-iter assignment-list body-list result)
    (cond ((not (null? assignment-list))
           (make-let-iter (cdr assignment-list)
                          body-list
                          (append result (list (car assignment-list)))))
          ((not (null? body-list))
           (make-let-iter assignment-list
                          (cdr body-list)
                          (append result (list (car body-list)))))
          (else result)))
  (let ((definition-list (definitions proc-body '()))
        (body-list (body-exps proc-body '())))
    (if (null? definition-list)
        proc-body
        (let ((let-body (list 'let definition-list)))
          (list (make-let-iter (make-assignment-list definition-list)
                               body-list let-body))))))

c.scan-out-definesをmake-procedureか、またはprocedure-bodyに組み込み、なぜそちらに組み込んだかを述べる

以下の要領でmake-procedureへ組み込む。構文解釈の部分なのでapply, user-printで使用されるprocedure-bodyで使用するより、evalのみで使用されるmake-procedureの方が適していると思われる。

(define (make-procedure parameters body env)
  (list 'procedure parameters (scan-defines body) env))