delay construct is used together with the procedure
force 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 the
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
#t if object is a promise; otherwise returns
#t if promise has been forced and its value cached;
If promise has been forced and its value cached, this procedure returns the cached value. Otherwise, an error is signalled.
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
define the expression
to have the same meaning as the procedure call
(make-promise (lambda () expression))
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
are supported in some implementations (none of these are currently
supported in MIT/GNU Scheme):
forceon an object that is not a promise may simply return the object.
#f, depending on the implementation:
(eqv? (delay 1) 1) ⇒ unspecified (pair? (delay (cons 1 2))) ⇒ unspecified
(+ (delay (* 3 7)) 13) ⇒ 34