use unsafe struct accessors and pair ops (using #%unsafe, because going throught scheme/unsafe/ops will lead to a cycle)
svn: r16744
This commit is contained in:
parent
82f10f35a5
commit
61e5c3e41e
|
@ -1,7 +1,8 @@
|
|||
(module promise '#%kernel
|
||||
(#%require "private/small-scheme.ss" "private/more-scheme.ss" "private/define.ss"
|
||||
(rename "private/define-struct.ss" define-struct define-struct*)
|
||||
(for-syntax '#%kernel "private/stxcase-scheme.ss"))
|
||||
(for-syntax '#%kernel "private/stxcase-scheme.ss")
|
||||
'#%unsafe)
|
||||
(#%provide lazy delay force promise? promise-forced? promise-running?)
|
||||
|
||||
;; This module implements "lazy" (composable) promises and a `force'
|
||||
|
@ -15,8 +16,12 @@
|
|||
;; that `force' is identity for non promise values), and `force'+`lazy'
|
||||
;; are sufficient for implementing the lazy language.
|
||||
|
||||
;; unsafe accessors
|
||||
(define-syntax pref (syntax-rules () [(_ p) (unsafe-struct-ref p 0)]))
|
||||
(define-syntax pset! (syntax-rules () [(_ p x) (unsafe-struct-set! p 0 x)]))
|
||||
|
||||
(define (promise-printer promise port write?)
|
||||
(let loop ([p (promise-val promise)])
|
||||
(let loop ([p (pref promise)])
|
||||
(cond [(reraise? p)
|
||||
(let ([v (reraise-val p)])
|
||||
(if (exn? v)
|
||||
|
@ -33,7 +38,7 @@
|
|||
(cond [(object-name p)
|
||||
=> (lambda (n) (fprintf port "#<promise:~a>" n))]
|
||||
[else (display "#<promise>" port)])]
|
||||
[(promise? p) (loop (promise-val p))] ; hide sharing
|
||||
[(promise? p) (loop (pref p))] ; hide sharing
|
||||
;; values
|
||||
[(null? p) (fprintf port "#<promise!(values)>")]
|
||||
[(null? (cdr p))
|
||||
|
@ -102,21 +107,21 @@
|
|||
(let loop1 ([v (p)]) ; does not handle multiple values!
|
||||
(if (promise? v)
|
||||
(let loop2 ([promise* v])
|
||||
(let ([p* (promise-val promise*)])
|
||||
(set-promise-val! promise* root) ; share with root
|
||||
(let ([p* (pref promise*)])
|
||||
(pset! promise* root) ; share with root
|
||||
(cond [(procedure? p*) (loop1 (p*))]
|
||||
[(promise? p*) (loop2 p*)]
|
||||
[else (set-promise-val! root p*)
|
||||
[else (pset! root p*)
|
||||
(cond [(null? p*) (values)]
|
||||
[(null? (cdr p*)) (car p*)]
|
||||
[(null? (unsafe-cdr p*)) (unsafe-car p*)]
|
||||
[else (apply values p*)])])))
|
||||
(begin ; error here for "library approach" (see above URL)
|
||||
(set-promise-val! root (list v))
|
||||
(pset! root (list v))
|
||||
v))))
|
||||
|
||||
(define (force promise)
|
||||
(if (promise? promise)
|
||||
(let loop ([p (promise-val promise)])
|
||||
(let loop ([p (pref promise)])
|
||||
(cond [(procedure? p)
|
||||
;; mark the root as running: avoids cycles, and no need to keep
|
||||
;; banging the root promise value; it makes this non-r5rs, but
|
||||
|
@ -124,26 +129,26 @@
|
|||
;; state to avoid an infinite loop.
|
||||
;; (careful: avoid holding a reference to the thunk, to allow
|
||||
;; safe-for-space loops)
|
||||
(set-promise-val! promise (make-running (object-name p)))
|
||||
(pset! promise (make-running (object-name p)))
|
||||
(call-with-exception-handler
|
||||
(lambda (e) (set-promise-val! promise (make-reraise e)) e)
|
||||
(lambda (e) (pset! promise (make-reraise e)) e)
|
||||
(lambda () (force-proc p promise)))]
|
||||
[(promise? p) (loop (promise-val p))]
|
||||
[(promise? p) (loop (pref p))]
|
||||
[(null? p) (values)]
|
||||
[(null? (cdr p)) (car p)]
|
||||
[(null? (unsafe-cdr p)) (unsafe-car p)]
|
||||
[else (apply values p)]))
|
||||
;; different from srfi-45: identity for non-promises
|
||||
promise))
|
||||
|
||||
(define (promise-forced? promise)
|
||||
(if (promise? promise)
|
||||
(let ([p (promise-val promise)])
|
||||
(let ([p (pref promise)])
|
||||
(or (not (procedure? p)) (reraise? p))) ; #f when running
|
||||
(raise-type-error 'promise-forced? "promise" promise)))
|
||||
|
||||
(define (promise-running? promise)
|
||||
(if (promise? promise)
|
||||
(running? (promise-val promise))
|
||||
(running? (pref promise))
|
||||
(raise-type-error 'promise-running? "promise" promise)))
|
||||
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue
Block a user