Analyze once, then run the plan many times.
An analyzer can turn expression data into a procedure that accepts an environment and performs only the remaining value lookups and operations.
Which work can be done before the expression receives an environment?
- Turn each expression node into an execution procedure
- Capture analyzed operand plans in a closure
- Reuse one plan with multiple environments
analyze walks the expression tree before any variable values are known. It selects each operator and recursively builds a procedure for every operand.
The resulting plan accepts an environment. Running it only looks up variables, runs the stored operand plans, and applies the already selected operator. One analyzed plan can therefore serve many environments.
(begin
(define (lookup name environment)
(cdr (assoc name environment)))
(define (operator-procedure name)
(cond ((eq? name '+) +)
((eq? name '*) *)))
(define (analyze expression)
(cond ((number? expression)
(lambda (environment) expression))
((symbol? expression)
(lambda (environment)
(lookup expression environment)))
(else
(let ((procedure (operator-procedure (car expression)))
(argument-plans (map analyze (cdr expression))))
(lambda (environment)
(apply procedure
(map (lambda (plan) (plan environment))
argument-plans)))))))
(let ((plan (analyze '(+ x (* y 2)))))
(list (plan '((x . 3) (y . 4)))
(plan '((x . 5) (y . 10))))))- Output
- —
- Value
- —
- Diagnostic
- —
The first program analyzes one expression and returns (11 25) from two environments.
Separate the initial analyze applications from the later plan applications. The expression structure is traversed once before either environment is supplied.
Change the program before you read the hint.
Add a third environment where x is 1 and y is 100. Reuse plan without calling analyze again.
Show one hint
Only add another plan application to the final list.