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 を先にやった方が良いのかなぁ。ちょっと頭がニエてる感じなのでリセット必要かも。