SICP 読み (168) 4.1.6 内部定義

早めに出勤してきたので以下を試してみた。

  • make-procedure で使っているのは lambda-body でこれはリストのリストになる
  • procedure-body で取り出すのもリストのリスト

という事は scan-out-defines で出力するソレも同様の形になっている必要あり。短気を起こして組み込んでしまう。scan-out-defines は以下のように修正。

(define (scan-out-defines exp)
  (define (make-set exp)
    (let f ((init '()) (set '()) (exp exp))
      (cond ((null? exp)
             (append (list 'let init) set))
            (else
             (cond ((definition? (car exp))
                    (f (append init (list (list (definition-variable (car exp))
                                                ''*unassigned*)))
                       (append set (list (list 'set!
                                               (definition-variable (car exp))
                                               (definition-value (car exp)))))
                       (cdr exp)))
                   (else
                    (f init set (cdr exp))))))))
  (append (make-set exp)
          (let f ((l '()) (exp exp))
            (cond ((null? exp) l)
                  ((definition? (car exp))
                   (f l (cdr exp)))
                  (else
                   (f (append l (list (car exp))) (cdr exp)))))))

試験も修正。まず、これを make-procedure に組み込んでみる。

make-procedure

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

で、試験してみるとなんかおかしい。以下の試験を追加してみると

    (let ((l1 '((+ a b)))
	  (l2 '((+ a b))))
      (assert-equal l2 (scan-out-defines l1))
      )

こうなった。(鬱

 expected:<((+ a b))>
  but was:<((let () (+ a b)))> in scan-out-defines

必ず let が付加されてしまう。馬鹿だなぁ。とりあえず急場シノギで以下のように修正。(なにが一発ツモか

(define (scan-out-defines exp)
  (define (make-set exp)
    (let f ((init '()) (set '()) (exp exp))
      (cond ((null? exp)
	     (if (null? init)
		 '()
		 (append (list 'let init) set)))
	    (else
	     (cond ((definition? (car exp))
		    (f (append init (list (list (definition-variable (car exp))
						''*unassigned*)))
		       (append set (list (list 'set!
					       (definition-variable (car exp))
					       (definition-value (car exp)))))
		       (cdr exp)))
		   (else
		    (f init set (cdr exp))))))))
  (let ((result (make-set exp)))
    (cond ((null? result) exp)
	  (else
	   (list 
	    (append result
		    (let f ((l '()) (exp exp))
		      (cond ((null? exp) l)
			    ((definition? (car exp))
			     (f l (cdr exp)))
			    (else
			     (f (append l (list (car exp))) (cdr exp)))))))))))

しかし長い。一応既存の試験にはパス。次は procedure-body か。

procedure-body

(define (procedure-body p) (scan-out-defines (caddr p)))

これも既存なソレにはパスしますな。両方に以下の試験を追加してみる。

   ("example"
    (let ((nenv (extend-environment '(tmp) '(0) 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-true (eval '(f 2) nenv))
      )
    )

で試験してみたんですが、どっちもパス。(当たり前

ちょっとネかせてみた方が良いのかなぁ。> 問題 4.16