[delay] and [lazy] are implemented as [promise],
which is a [struct] containing a mutable filed (pointer).
[lazy] implements a composable promise: a single [force] iterates
through the whole chain of composed [lazy] objects, tail-calling each step.
A promise can hold
Black holes as exceptions is non-r6rs. [1,2] discuss a faster implementation of composable promises by not keep banging the root promise value on each iteration.
(Generic) promises are forced in a standard fashion: update the promise with an exception-raising thunk, force the promise by calling the thunk held by the promise and update the promise with the value thus computed.
Carefully force composable promises, so that it is space-safe and
tail-calling.
For
let rec x1 = lazy x2 and x2 = lazy x3 and x3 = lazy 4we get
x2 -> x1 -> 4 x3For
let rec x1 = lazy x2 and x2 = delay (force x3) and x3 = delay 4we get
x1 -> x2 -> 4 x3 -> 4
This structure is partially visible in the error messages from the following programs.
(define a (letrec ([a (lazy b)] [b (lazy c)] [c (lazy b)]) a)) (force a) force: reentrant promise 'aSo b is redirected to a.
(define b (letrec ([a (delay (force b))] [b (delay (force c))] [c (delay (force b))]) a)) (force b) force: reentrant promise 'bNo sharing.
(define c (letrec ([a (lazy b)] [b (delay (force a))]) a)) (force c) force: reentrant promise 'ba is redirected to b.
(define d (letrec ([a (lazy (force b))] [b (delay (force a))]) a)) (force d) force: reentrant promise 'aNo sharing.
(define e (letrec ([a (lazy b)] [b (delay (force c))] [c (lazy d)] [d (delay (force a))]) a)) (force e) force: reentrant promise 'bNothing new.