sicp.io
4.2.2 · An interpreter with lazy evaluation

A memoized thunk performs demanded work at most once.

Delay compound-procedure operands, force primitive operands and predicates, and rewrite a thunk into an evaluated-thunk after its first actual-value request.

Guiding question

How can an evaluator postpone argument work while preventing repeated references from recomputing the same expression?

  • Delay operand expressions together with their calling environments
  • Force an operator before deciding how to apply it
  • Force every primitive argument and if predicate to an actual value
  • Pass delayed arguments to compound procedures
  • Memoize a thunk by changing its tag and stored payload
  • Observe unused, repeated, and unselected expressions separately

apply-lazy distinguishes host primitives from represented compound procedures. A primitive needs actual argument values, so its operands are forced before host apply. A compound procedure instead receives thunk records containing the original operand expressions and calling environment. Variable lookup returns that record, and actual-value decides whether it must be forced.

force-it evaluates a fresh thunk once, rewrites the same mutable record to evaluated-thunk, stores the result, and discards the saved expression and environment. The unused argument therefore performs no probe. The duplicated x expression is demanded twice but probes once. The false branch of the selected if is never evaluated. This evaluator implements call by need for the listed forms under an explicit work budget.

SICP code7,892 of 1,048,576 UTF-8 bytes
Examples
Result
Output
Value
Diagnostic
Execution trace0 / 0 events
    Programs run in the browser with their result and execution trace.
    Expected result

    The evaluator returns ((unused 1 0) (duplicated 20 1) (branch safe 0)).

    Trace focus

    Follow compound application into list-of-delayed-args, then find the first lookup that sends a thunk to force-it. Verify the record mutation to evaluated-thunk and the second lookup returning the cached value. In the if expression, confirm that only the predicate and selected consequent are evaluated.

    Try it yourself

    Change the program and compare the result.

    Add ((lambda (x) (+ x (+ x x))) (probe 4)) and predict the value and probe count. Then remove the thunk mutation in force-it and compare the result.

    Show hint

    With memoization the argument probes once no matter how many x lookups occur. Without mutation, every lookup re-evaluates the saved expression.

    Complete this lesson

    0 of 23 lessons complete in this chapter0%