FWIW, here is an implementation of lazy/eager/delay/force that works
with multiple values. Additional notes:
* Works on PLT, but this is mostly a technicality. One thing is that
some diverging tests fail on PLT v352, but everything seems to work
fine on v352.7 (we think that it's because Matthew did some work on
optimizing `call-with-values' recently).
* Requires `eager' to be a syntax too, so it can handle multiple
values.
* Clarifies the relationship between plain `delay' and `lazy' (close
to the Dybvig implementation that is used in MzScheme). The latter
is similar, but injects an extra level of reference, to
short-circuit force chains.
(define-struct promise (p))
(define-syntax lazy
(syntax-rules ()
[(lazy exp) (box (make-promise (lambda () exp)))]))
(define-syntax eager
(syntax-rules ()
[(eager exp)
(box (make-promise (call-with-values (lambda () exp) list)))]))
(define-syntax delay
(syntax-rules () [(delay exp) (lazy (eager exp))]))
(define (force boxed)
(let* ([promise (unbox boxed)]
[content (promise-p promise)])
(if (procedure? content)
(let* ([boxed* (content)]
[promise (unbox boxed)]) ; *
(when (procedure? (promise-p promise)) ; *
(set-promise-p! promise (promise-p (unbox boxed*)))
(set-box! boxed* promise))
(force boxed))
(apply values content))))
;; (*) These two lines re-fetch and check the original promise in case
;; the first line of the let* caused it to be forced. For an example
;; where this happens, see reentrancy test 3 below.
--
((lambda (x) (x x)) (lambda (x) (x x))) Eli Barzilay:
http://www.barzilay.org/ Maze is Life!