Rewrite new syntax into a rule the evaluator already knows.
A let expression can be translated into a lambda application, keeping the evaluator core smaller while preserving the binding behavior.
What must remain unchanged when let is rewritten as a lambda application?
- Separate surface syntax from evaluator core forms
- Collect binding names as lambda parameters
- Collect binding expressions as application operands
- Evaluate the transformed expression in the original environment
The transformer takes the binding names from let and places them in a lambda parameter list. It puts the let body in that lambda and places the binding expressions after the lambda as application operands.
The evaluator does not need a second implementation of local binding. Its let case rewrites the expression and sends the result back through the ordinary lambda and application cases in the same environment.
(begin
(define (binding-name binding) (car binding))
(define (binding-value binding) (cadr binding))
(define (let->combination expression)
(let ((bindings (cadr expression))
(body (caddr expression)))
(cons (list 'lambda (map binding-name bindings) body)
(map binding-value bindings))))
(let->combination '(let ((x 10) (y 32)) (+ x y))))- Output
- —
- Value
- —
- Diagnostic
- —
The first program returns ((lambda (x y) (+ x y)) 10 32). The second returns 42.
In the second run, find the let dispatch and the transformer calls before the lambda is created. The later application extends the environment with x and y, then evaluates the original body.
Change the program before you read the hint.
Add a z binding with value 8 and change the body to (+ (+ x y) z). Predict both the transformed expression and its value.
Show one hint
The parameter and operand lists grow in the same order. The body remains one expression inside the lambda.