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))