Exercise 4.7

今度は let* 式を等価の let 式に変形する問題

(define (make-let bind body)
  (cons 'let (cons bind body)))
(define (let-parameters exp) (map car (car exp)))
(define (let-arguments exp) (map cadr (car exp)))
(define (let-bind exp) (cadr exp))
(define (let-body exp) (cddr exp))
(define (let-first-bind exp) (car exp))
(define (let-rest-bind exp) (cdr exp))

(define (let*->nested-lets exp)
  (let*->nested-lets-iter (let-bind exp) (let-body exp)))
(define (let*->nested-lets-iter bind body)
  (make-let (list (let-first-bind bind))
            (if (null? (let-rest-bind bind))
              body
              (list (let*->nested-lets-iter (let-rest-bind bind) body)))))

実際に動かしてみて

gosh> (let*->nested-lets  '(let* ((x 3) (y (+ x 2))) (+ x y) (* x y)))
(let ((x 3)) (let ((y (+ x 2))) (+ x y) (* x y)))

となるので、let式への展開は OK。
ただし、これをさらに Exercise 4.6 で作成した let->combination で lambda まで展開させた場合、

(let->combination  (let*->nested-lets  '(let* ((x 3) (y (+ x 2))) (+ x y) (* x y))))
((lambda (x) (let ((y (+ x 2))) (+ x y) (* x y))) 3)

と、一番外側の let しか展開されないので、そのまま評価器の eval に乗せることはできない。