問題4.16 – SICP(計算機プログラムの構造と解釈)その188

問題4.16

a. lookup-variable-value に、値が *unassigned* の場合にエラーを返す処理を追加する。

(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? '*unassigned* (car vals))
                 (error "Unassigned variable -- LOOKUP-VARIABLE-VALUE" 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 手続きを定義する。

(define (scan-out-defines body)
  (define (iter exp vars sets exps)
    (if (null? exp)
        (list (reverse vars) (reverse sets) (reverse exps))
        (if (definition? (car exp))
            (iter (cdr exp) (cons (list (definition-variable (car exp)) ''*unassigned*) vars) (cons (list 'set! (definition-variable(car exp)) (definition-value (car exp))) sets) exps)
            (iter (cdr exp) vars sets (cons (car exp) exps)))))
  (define (include-define? exp)
    (if (null? exp)
        #f
        (if (definition? (car exp))
            #t
            (include-define? (cdr exp)))))
  (if (include-define? body)
      (let ((var-val-exp-list (iter body '() '() '())))
           (list (cons 'let (cons (car var-val-exp-list) (append (cadr var-val-exp-list) (caddr var-val-exp-list))))))
      body))

実行結果

;;; M-Eval input:
(define foo (lambda (x)
                    (define a 1)
                    (define b 2)
                    (* (+ a x) b)))

;;; M-Eval value:
ok

;;; M-Eval input:
(foo 7)

;;; M-Eval value:
16

;;; M-Eval input:
(define (f x)
  (define (even? n)
    (if (= n 0)
        true
        (odd? (- n 1))))
  (define (odd? n)
    (if (= n 0)
        false
        (even? (- n 1))))
  (cond ((even? x) 'even)
        ((odd? x) 'odd)))

;;; M-Eval value:
ok

;;; M-Eval input:
(f 5)

;;; M-Eval value:
odd

;;; M-Eval input:
(f 6)

;;; M-Eval value:
even

c. scan-out-defines を組み込む適切な場所。

どちらに組み込んでもきちんと動作するが、procedure-body に組み込むと applyuser-print 手続きで呼ばれるのに対し、make-procedure に組み込めば eval の際のみに呼ばれるから make-procedure がよい。
と、思ったら、他の人の解答例では procedure-body に組み込んでいる例の方が多かった…

計算機プログラムの構造と解釈
ジェラルド・ジェイ サスマン ジュリー サスマン ハロルド エイブルソン
ピアソンエデュケーション
売り上げランキング: 6542
«
»