SICP 読み (165) 4.1.6 内部定義
問題 4.16 の前に
まず、例示されている手続き (最後のみ手を入れとりますが)
(define (f x) (define (even? n) (if (= n 0) true (odd? (- n 1)))) (define (odd? n) (if (= n 0) false (even? (- n 1)))) (even? x))
がどのように評価されるか、を確認。上記リストが eval に渡されると definition? が真判定なはずなので、eval-definition によってリストが評価される。
その eval-definition の中の define-variable! に渡されるのは手続きの名前 f と
(lambda (x) (define (even? n) (if (= n 0) true (odd? (- n 1)))) (define (odd? n) (if (= n 0) false (even? (- n 1)))) (even? x))
lambda 式に変換された手続き部分を eval したものになる。以下の試験で確認。
("4.1.6" ("example" (let ((nenv (extend-environment '(a) '(1) the-global-environment))) (eval '(define (f x) (define (even? n) (if (= n 0) true (odd? (- n 1)))) (define (odd? n) (if (= n 0) false (even? (- n 1)))) (even? x)) nenv) (assert-equal 'procedure (car (lookup-variable-value 'f nenv))) (assert-equal '(x) (cadr (lookup-variable-value 'f nenv))) (assert-equal '((define (even? n) (if (= n 0) true (odd? (- n 1)))) (define (odd? n) (if (= n 0) false (even? (- n 1)))) (even? x)) (caddr (lookup-variable-value 'f nenv))) (assert-true (eval '(f 2) nenv)) ) ) )
この lambda? な eval の時に適用されるのが make-procedure になっていて上記で確認している形なリストが作成されて f に束縛されている、というのが例示された define なリストを eval した状態。
apply してみる
次はその手続きを eval してみる。
(let ((nenv (extend-environment '(a) '(1) the-global-environment))) (eval '(define (f x) (define (even? n) (if (= n 0) true (odd? (- n 1)))) (define (odd? n) (if (= n 0) false (even? (- n 1)))) (even? x)) nenv) (eval '(f 2) nenv) )
(f 2) というリストは application 認定されるんで以下の式が適用される。
(apply (eval 'f env) (list-of-values '(2) env))
f は先の define で手続きが束縛されている状態。procedure で始まるリストが戻る。apply の中では compound-procedure 認定され、
(eval-sequence ;; (procedure-body procedure) '((define (even? n) (if (= n 0) true (odd? (- n 1)))) (define (odd? n) (if (= n 0) false (even? (- n 1)))) (even? x)) (extend-environment '(x) '(2) ;; (procedure-environment procedure) env))
みたいな形になるはず。上記を見てはじめて気がついたんですが、一連の手続きが eval される環境は手続きを定義した環境に引数の束縛を extend-environment したものなのか。
後は手続きが順に取り出されて eval されていく、と。
問題 4.16 の c
scan-out-defines は例えば上記の例だと make-procedure が
'((define (even? n) (if (= n 0) true (odd? (- n 1)))) (define (odd? n) (if (= n 0) false (even? (- n 1)))) (even? x))
なリストを戻す前に
'(let ((even? '*unassigned*) (odd? '*unassigned*)) (set! even? '(lambda (n) (if (= n 0) true (odd? (- n 1))))) (set! odd? '(lambda (n) (if (= n 0) false (even? (- n 1))))) (even? x))
に変換する方のが良いのか、あるいは apply から呼ばれる eval-sequence における procedure-body で変換された方が良いのか、という話なのかなぁ。
それだけだとどちらもあまり変わりがないように感じる。
ちょっと何かを勘違いしているのかなぁ。別途再確認。ってか a とか b を先にやった方が良いのかなぁ。ちょっと頭がニエてる感じなのでリセット必要かも。