[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Multiple values

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

* 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!