SICP 読み (343) 5.5 翻訳系

昨晩のソレを元に検討着手。とりあえず以前のエントリをカンニングだ。

どーでも良い話なんですが、5 章に突入してから 100 エントリ位消費してるんでしょうか。自分でヤッててナニですが滅茶苦茶だな。

問題 5.43

ええと何ヤレば良いんだっけ。(こら
これが

(define (factorial n)
  (define (iter product counter)
    (if (> counter n)
	product
	(iter (* counter product)
	      (+ counter 1))))
  (iter 1 1))

こうなって

(define factorial
  (lambda (n)
    (define (iter product counter)
      (if (> counter n)
	  product
	  (iter (* counter product)
		(+ counter 1))))
    (iter 1 1)))

scan-out-defines でこうなってくれ

(define factorial
  (lambda (n)
    (let ((iter '*unassigned*))
      (set! iter (lambda (product counter)
		   (if (> counter n)
		       product
		       (iter (* counter product)
			     (+ counter 1)))))
      (iter 1 1))))

で let->combination でこうなってくれたものを

(define factorial
  (lambda (n)
    ((lambda (iter)
       (set! iter (lambda (product counter)
		    (if (> counter n)
			product
			(iter (* counter product)
			      (+ counter 1)))))
       (iter 1 1))
     '*unassigned*)))

compile で翻訳できれば万歳。ってそんなに簡単に行くのかどうか。

つづき

って正確には一番てっぺんの式が compile に吸われた後は definition-value が lambda な式に直して compile に吸われる。これは compile-lambda が取り扱い責任者なんですが、この間で何とかしないと駄目だな。compile-lambda-body に渡る時点でもまだセイフかな。compile-sequence に渡る直前までに何とかしておく必要ありか。
あるいは

(compile-sequence (lambda-body exp) 'val 'return)

なソコで ... ってワケ分からんから gosh で試す。

gosh> (add-load-path ".")
gosh> (load "ch5-syntax")
gosh> (define scan-out-defines 略)
gosh> (scan-out-defines '((+ a b)))
((+ a b))
gosh> (scan-out-defines '((define (iter product counter)
      (if (> counter n)
          product
          (iter (* counter product)
                (+ counter 1))))
    (iter 1 1)))
((let ((iter '*unassigned*)) (set! iter (lambda (product counter) (if (> counter n) product (iter (* counter product) (+ counter 1))))) (iter 1 1)))
gosh> 

む。イケてる感じ。もう少し。ってここでいきなり let->combination に吸わせてハマる。compile に let->combination が仕込んであればいいんだからこうか

(compile-sequence (compile (scan-out-defines (lambda-body exp)) 'val 'next) 'val 'return)

中の compile な引数が微妙。しかも現時点で *unassigned* なソレを完全にスルーしてるしー。
とりあえず使用予定な手続き定義もメモ。

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

(define (let->combination exp)
  (append (list (make-lambda (map car (cadr exp)) (cddr exp)))
	  (map cadr (cadr exp))))

しかし上記の scan-out-defines は今見るとミニクい。名前 let な内部手続きをうれしがって使ってた頃だなぁ。ちょっと手を入れてみるか。

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

試験は別途とゆーコトでとりあえず投入。

エントリ投入時に気づいた

let でないかもしれんのに

(compile-sequence (compile (scan-out-defines (lambda-body exp)) 'val 'next) 'val 'return)

なコトしちゃ駄目ぢゃん。てか compile-sequence の中で個別に compile してるから let->combination は compile に組み込まれてれば

(compile-sequence (scan-out-defines (lambda-body exp)) 'val 'return)

で良さげ。

追記

手を入れた微妙な scan-out-defines ですが、誤りがあったので修正しとります。まだ微妙なカンジ。