thunk — thunk — a computation boxed and shelved, evaluated only if forced
thunk [--lazy] [--memoize] [--never] EXPRESSION force(thunk) -> value // first call only cost(ask twice) = cost(ask once) iff --memoize
thunk wraps EXPRESSION in a zero-argument closure and returns immediately. Nothing in EXPRESSION runs. The wrapper is cheap; the work inside is deferred until something calls force() on it, an event that may occur once, many times, or never.
With --memoize the thunk overwrites itself with its result on first force and answers instantly thereafter. Without it, each force re-runs the whole expression, faithfully, at full price. thunk does not decide which is correct. thunk only defers.
A thunk over an infinite structure is legal and common. It represents work the machine could do but has declined to, pending demand that has not arrived.
"The term was coined around 1961 by P. Z. Ingerman's ALGOL 60 compiler group to name the closures generated for call-by-name arguments, which are re-evaluated on each mention. The name is the jocular past tense of think: the value had already been thunk of by the compiler. Chris Wadsworth's 1971 thesis added self-overwriting evaluation, giving call-by-need and the once-only thunk. Microsoft later reused the word for its 16-bit/32-bit interoperability stubs, unrelated machinery under the same name."
Under call-by-name, asking twice costs twice. Reported as a performance defect since 1961. Reclassified as intended behavior.
A thunk chain can retain its entire environment in memory long after the value would have fit in a register. Known as a space leak. Not a leak, technically; nothing escaped.
--never has no observable output, which some users mistake for failure. It is the success case.
quiescence(8), backpressure(3), idempotent(1). The living exhibit demonstrates the word in motion:
▸ operate thunk