ruandao / blog

0 stars 0 forks source link

[16.1.10] [sicp 4.7] #143

Closed ruandao closed 8 years ago

ruandao commented 8 years ago
Exercise 4.7.  Let* is similar to let, except that the bindings of the let variables are performed sequentially from left to right, and each binding is made in an environment in which all of the preceding bindings are visible. For example

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

returns 39. Explain how a let* expression can be rewritten as a set of nested let expressions, and write a procedure let*->nested-lets that performs this transformation. If we have already implemented let (exercise 4.6) and we want to extend the evaluator to handle let*, is it sufficient to add a clause to eval whose action is

(eval (let*->nested-lets exp) env)

or must we explicitly expand let* in terms of non-derived expressions?
ruandao commented 8 years ago
(load "apply-eval.scm")

(define install-let
  (lambda()
    (define (make-lambda args body)
      ((get-proc '(make-lambda)) args body))

    (define (let? exp)
      (tagged-list? exp 'let))
    (define (make-let assignments body)
      (list 'let assignments body))
    (define (let-assignments let-clause)
      (cadr let-clause))
    (define (let-body let-clause)
      (caddr let-clause))

    (define (eval-let exp env)
      (let ((new-exp (cons (make-lambda
                (map car (let-assignments exp))
                (let-body exp))
               (map cadr (let-assignments exp)))))
    (eval new-exp env)))

    (put-type-query! let? '(let))
    (put-proc! '(eval let) eval-let)
    (put-proc! '(make-let) make-let)
    ))

(define install-let*
  (lambda()
    (install-let)

    (define (make-let args body)
      ((get-proc '(make-let)) args body))

    (define (let*? exp)
      (tagged-list? exp 'let*))
    (define (make-let* assignments body)
      (list 'let* assignments body))
    (define (let*-assignments let-clause)
      (cadr let-clause))
    (define (let*-body let-clause)
      (caddr let-clause))

    (define (expand-let* assignments body)
      (cond
       ((null? (cdr assignments))
    (make-let assignments body))
       (else
    (make-let (list (car assignments))
          (expand-let* (cdr assignments) body)))))
    (define (let*->nested-lets exp)
      (expand-let* (let*-assignments exp)
           (let*-body exp)))
    (define (eval-let* exp env)
      (eval (let*->nested-lets exp) env))

    (put-type-query! let*? '(let*))
    (put-proc! '(eval let*) eval-let*)
    (put-proc! '(make-let*) make-let*)
    ))