(Lispex)sicp.io
4.6 · Evaluation strategy as data

A thunk delays work and remembers its value.

A tagged mutable object can hold a suspended computation, then replace that representation with the value produced by its first force.

Guiding question

Which representation changes make call-by-need visible inside an evaluator?

  • Represent delayed work as a tagged mutable vector
  • Distinguish an unevaluated thunk from an evaluated thunk
  • Force a suspended computation only when its value is demanded
  • Memoize the first value for later demands

make-thunk stores a thunk tag, a zero-argument computation, and an empty result slot. Creating that vector does not call the computation, so even a body that would fail can remain harmless when nobody demands it.

force-it inspects the tag. On the first demand it calls the stored computation, changes the tag to evaluated-thunk, discards the computation, and stores the value. Later demands select the cached slot and perform no computation again. This exposes the representation change that a lazy evaluator normally hides behind argument handling.

Lispex · SICP sourceScheme-compatible SICP syntax executed by the Lispex SICP profile.
(begin
  (define (make-thunk computation)
    (vector 'thunk computation #f))
  (define (force-it object)
    (if (eq? (vector-ref object 0) 'evaluated-thunk)
        (vector-ref object 2)
        (let ((value ((vector-ref object 1))))
          (vector-set! object 0 'evaluated-thunk)
          (vector-set! object 1 #f)
          (vector-set! object 2 value)
          value)))
  (define calls 0)
  (define delayed
    (make-thunk
      (lambda ()
        (set! calls (+ calls 1))
        (* calls 10))))
  (list (force-it delayed)
        (force-it delayed)
        calls
        (vector-ref delayed 0)))
Lispex learning runtimeLispex SICP profile 1.0.0
Loading Lispex SICP runtime
Lispex · SICP source607 / 1,048,576 UTF-8 bytes
Examples
Result
Output
Value
Diagnostic
Visible execution0 / 0 trace events
    This browser result is not a Lispex Vouch record or authority.wasm —
    Expected observation

    The first program returns (10 10 1 evaluated-thunk). The second returns (thunk 0) without evaluating the division by zero.

    Trace focus

    In the first run, find one application of the stored computation and the vector mutations that replace the thunk representation. The second force reads the cached value. In the second run, confirm that no division application or calls assignment occurs.

    Try it yourself

    Change the program before you read the hint.

    Force delayed a third time in the first program. Predict the three values, calls count, and final tag before running it.

    Show one hint

    Once the tag is evaluated-thunk, force-it reads slot 2 without calling slot 1.