問題4-16

「4.1.6 内部定義」に入りました。四章の第一節もゴールが見えてきましたが、このトピックは問題が多く、しかも一筋縄では解けそうにないので、ちょっと参っています。
問題4-16を解く前に、問題4-6で定義した自前のletが正しく動くかを試してみました。結果はダメでした。ここブログの解答例で試してみたら動きました。以下がそれですが、どうやら自分の定義は、大筋では正しかったものの、細かいリスト内の要素の取得ロジックに問題があったようです。

(define (let? exp)
  (tagged-list? exp 'let))

(define (let-variables exp)
  (map car (cadr exp)))

(define (let-expressions exp)
  (map cadr (cadr exp)))

(define (let-body exp)
        (cddr exp))

(define (let->combination exp)
  (cons (make-lambda (let-variables exp)
		      (let-body exp))
	 (let-expressions exp)))

問題4-16の内部定義を変換するscan-out-defineについてですが、手続き本体にdefineがあったら、let式に変換していき、'*unassaigned*で束縛したり、set!で変更したりする手続きを組み込んでやればよさそうです。ただ、上手く書けなそうだったので、ここのエントリーで描かれていたコードを参考にしました。非常に上手く書かれていて、すんなりと納得することができました。
問題4-17については、let式変換バージョンだと、letがevalされた時にlambda式に変換され、そのlambdaはmake-procedureによってcompond-procedureとなり、こうなるとapply時にextend-environmentによって新しいフレームが作成されるから、問題文に書いてあるような状態になるのではと思いましたが、これ以上思考が進まなかったため、深追いするのはやめました。