4.8 Exercise 4.8
In order to support the named let form, we can check whether the second element of the let expression is a list or not. If it is a list, then we are using a standard let expression. If it is a variable, then we have a named let.
First, we define a predicate for determining if an expression (which is already assumed to be a let expression of some form) is a named let expression, and write new accessors for it:
(define (named-let? exp) (variable? (cadr exp))) (define (named-let-name exp) (cadr exp)) (define (named-let-bindings exp) (caddr exp)) (define (named-let-parameters exp) (map car (named-let-bindings exp))) (define (named-let-initial-values exp) (map cadr (named-let-bindings exp))) (define (named-let-body exp) (cdddr exp))
Next we define the new version of let->combination, which chooses to reduce a named let expression to a define (since we need to call this procedure recursively, it needs a name, and this is how we know how to do this). I’ve also defined a make-define procedure in line with the other make- procedures. Note that this define is wrapped inside a let with no bindings – this is required for the expression to be legal.
(define (make-define binding val) (list 'define binding val))
(define (let->combination exp) (if (named-let? exp) (make-let '() (make-define (named-let-name exp) (make-lambda (named-let-parameters exp) (named-let-body exp))) (cons (named-let-name exp) (named-let-initial-values exp))) (list (make-lambda (let-names exp) (let-body exp)) (let-values exp))))