SICP問題4.7

2010/03/17 evalでlookup-variable-valueのトコが間違ってたので修正
2010/03/16 4.9のmake-named-letに合わせてmake-letを修正

問題のlet*式の例

(let* ((x 3)
       (y (+ x 2))
       (z (+ x y 5)))
  (* x z))
; 39

これは以下のようなletに書き換えることが可能である。

(let ((x 3))
  (let ((y (+ x 2)))
    (let ((z (+ x y 5)))
      (* x z))))
; 39

ということで以下の要領でlet*->nested-letsを実装する。
let*関連の手続き

(define (let*? exp)
  (tagged-list? exp 'let*))
(define (let*-parameters exp)
  (cadr exp))
(define (let*-body exp)
  (caddr exp))
(define (make-let parameters body)
  (cons 'let (list parameters body)))
(define (let*->nested-lets exp)
  (define (iter reverse-parameters result)
    (if (null? reverse-parameters)
        result
        (iter (cdr reverse-parameters)
              (make-let (list (car reverse-parameters)) result))))
  (iter (reverse (let*-parameters exp))
        (let*-body exp)))

(データ主導型でない)evalへの組み込み

(define (eval exp env)
  (cond ((self-evaluating? exp) exp)
        ((variable? exp) (lookup-variable-value exp env))
        ((quoted? exp) (text-of-quotation exp))
        ((assignment? exp) (eval-assignment exp env))
        ((definition? exp) (eval-definition exp env))
        ((if? exp) (eval-if exp env))
        ((lambda? exp)
         (make-procedure (lambda-parameters exp)
                         (lambda-body exp)
                         env))
        ((let? exp) (eval (let->combination exp) env))
        ((let*? exp) (eval (let*->nested-lets exp) env)) ; 追加
        ((begin? exp)
         (eval-sequence (begin-actions exp) env))
        ((cond? exp) (eval (cond->if exp) env))
        ((and? exp) (eval-and exp env))
        ((or? exp) (eval-or exp env))
        ((application? exp)
         (apply (eval (operator exp) env)
                (list-of-values (operands exp) env)))
        (else
         (error "Unknown expression type -- EVAL" exp))))