Next: Streams, Previous: Records, Up: Miscellaneous Datatypes
The
delay
construct is used together with the procedureforce
to implement lazy evaluation or call by need.(delay
expression)
returns an object called a promise which at some point in the future may be asked (by theforce
procedure) to evaluate expression and deliver the resulting value.
Forces the value of promise. If no value has been computed for the promise, then a value is computed and returned. The value of the promise is cached (or “memoized”) so that if it is forced a second time, the previously computed value is returned without any recomputation.
(force (delay (+ 1 2))) => 3 (let ((p (delay (+ 1 2)))) (list (force p) (force p))) => (3 3) (define head car) (define tail (lambda (stream) (force (cdr stream)))) (define a-stream (letrec ((next (lambda (n) (cons n (delay (next (+ n 1))))))) (next 0))) (head (tail (tail a-stream))) => 2
Returns
#t
if promise has been forced and its value cached; otherwise returns#f
.
If promise has been forced and its value cached, this procedure returns the cached value. Otherwise, an error is signalled.
force
and delay
are mainly intended for programs written
in functional style. The following examples should not be considered to
illustrate good programming style, but they illustrate the property that
the value of a promise is computed at most once.
(define count 0) (define p (delay (begin (set! count (+ count 1)) (* x 3)))) (define x 5) count => 0 p => #[promise 54] (force p) => 15 p => #[promise 54] count => 1 (force p) => 15 count => 1
Here is a possible implementation of delay
and force
. We
define the expression
(delay expression)
to have the same meaning as the procedure call
(make-promise (lambda () expression))
where make-promise
is defined as follows:
(define make-promise (lambda (proc) (let ((already-run? #f) (result #f)) (lambda () (cond ((not already-run?) (set! result (proc)) (set! already-run? #t))) result))))
Promises are implemented here as procedures of no arguments, and
force
simply calls its argument.
(define force (lambda (promise) (promise)))
Various extensions to this semantics of delay
and force
are supported in some implementations (none of these are currently
supported in MIT/GNU Scheme):
force
on an object that is not a promise may simply
return the object.
#t
or #f
,
depending on the implementation:
(eqv? (delay 1) 1) => unspecified (pair? (delay (cons 1 2))) => unspecified
car
and
+
:
(+ (delay (* 3 7)) 13) => 34