racket/stream: unbreak chained lazy streams
The new implementation attempting to collapse lazy streams was broken.
This commit is contained in:
parent
a5615a7bae
commit
e31003b0ad
|
@ -134,6 +134,17 @@
|
|||
(in-parallel '(1 3) '(2 4))))))
|
||||
list)
|
||||
|
||||
;; check `#:eager`
|
||||
(test #t stream? (stream-cons (/ 1 0) (/ 1 0)))
|
||||
(test #t stream? (stream-cons #:eager 1 (/ 1 0)))
|
||||
(test #t stream? (stream-cons (/ 1 0) #:eager '(1)))
|
||||
(test #t stream? (stream-cons #:eager 0 #:eager '(1)))
|
||||
(err/rt-test (stream-cons 1 #:eager (/ 1 0)))
|
||||
(err/rt-test (stream-cons #:eager (/ 1 0) '(1)))
|
||||
(err/rt-test (stream-cons #:eager (/ 1 0) #:eager '(1)))
|
||||
(err/rt-test (stream-cons #:eager 1 #:eager (/ 1 0)))
|
||||
(err/rt-test (stream-cons #:eager 1 #:eager 1))
|
||||
|
||||
;; stream-rest doesn't force rest expr
|
||||
(test #t stream? (stream-rest (stream-cons 1 'oops)))
|
||||
|
||||
|
@ -178,4 +189,9 @@
|
|||
(letrec ([s (stream-cons 1 (stream-force (stream-rest s)))])
|
||||
(err/rt-test (stream-empty? (stream-rest s)) exn:fail:contract? #rx"reentrant or broken"))
|
||||
|
||||
;; regression test for chain of lazy streams
|
||||
(test 1 stream-first (stream-lazy
|
||||
(stream-lazy
|
||||
(stream-lazy '(1)))))
|
||||
|
||||
(report-errs)
|
||||
|
|
|
@ -33,10 +33,10 @@
|
|||
(lambda (p) (stream-force-first p))
|
||||
(lambda (p) (eagerly-created-stream-rest p))))
|
||||
|
||||
;; A lazily constructed stream uses an mpair redirection to facilitate
|
||||
;; flattening chains of lazily constructed streams. The pair starts with
|
||||
;; #f if the stream is forced, a symbol for the constructing form otherwise
|
||||
(define-struct lazily-created-stream (mpair)
|
||||
;; A lazily constructed stream starts with #f if the stream is forced,
|
||||
;; a symbol for the constructing form otherwise; a #t in place of a
|
||||
;; symbol means 'stream-cons
|
||||
(define-struct lazily-created-stream (creator-if-unforced thunk-or-stream)
|
||||
#:mutable
|
||||
#:reflection-name 'stream
|
||||
#:property for:prop:stream (vector
|
||||
|
@ -52,9 +52,9 @@
|
|||
(define-syntax stream-lazy
|
||||
(syntax-rules ()
|
||||
[(stream-lazy expr)
|
||||
(make-lazily-created-stream (mcons 'stream-lazy (lambda () expr)))]
|
||||
(make-lazily-created-stream 'stream-lazy (lambda () expr))]
|
||||
[(stream-lazy #:who who-expr expr)
|
||||
(make-lazily-created-stream (mcons (or who-expr 'stream-lazy) (lambda () expr)))]))
|
||||
(make-lazily-created-stream (or who-expr 'stream-lazy) (lambda () expr))]))
|
||||
|
||||
(define reentrant-error
|
||||
(lambda () (raise-arguments-error 'stream "reentrant or broken delay")))
|
||||
|
@ -63,34 +63,40 @@
|
|||
(define (stream-force s)
|
||||
(cond
|
||||
[(lazily-created-stream? s)
|
||||
(define p (lazily-created-stream-mpair s))
|
||||
(cond
|
||||
[(not (mcar p)) (mcdr p)]
|
||||
[else
|
||||
(define thunk (mcdr p))
|
||||
(set-mcdr! p reentrant-error)
|
||||
(define v (thunk))
|
||||
(cond
|
||||
[(lazily-created-stream? v)
|
||||
;; flatten the result lazy stream and try again
|
||||
(set-lazily-created-stream-mpair! s (lazily-created-stream-mpair v))
|
||||
(stream-force v)]
|
||||
[(for:stream? v)
|
||||
;; any other kind of stream is success
|
||||
(set-mcar! p #f)
|
||||
(set-mcdr! p v)
|
||||
v]
|
||||
[else
|
||||
(define who (mcar p))
|
||||
(if (symbol? who)
|
||||
(raise-arguments-error
|
||||
who
|
||||
"delayed expression produced a non-stream"
|
||||
"result" v)
|
||||
(raise-arguments-error
|
||||
'stream-cons
|
||||
"rest expression produced a non-stream"
|
||||
"rest result" v))])])]
|
||||
(let loop ([s s] [dep-ses '()])
|
||||
(cond
|
||||
[(not (lazily-created-stream-creator-if-unforced s))
|
||||
(define v (lazily-created-stream-thunk-or-stream s))
|
||||
(for ([dep-s (in-list dep-ses)])
|
||||
(set-lazily-created-stream-creator-if-unforced! dep-s #f)
|
||||
(set-lazily-created-stream-thunk-or-stream! dep-s v))
|
||||
v]
|
||||
[else
|
||||
(define thunk (lazily-created-stream-thunk-or-stream s))
|
||||
(set-lazily-created-stream-thunk-or-stream! s reentrant-error)
|
||||
(define v (thunk))
|
||||
(cond
|
||||
[(lazily-created-stream? v)
|
||||
;; try again
|
||||
(loop v (cons s dep-ses))]
|
||||
[(for:stream? v)
|
||||
;; any other kind of stream is success
|
||||
(set-lazily-created-stream-creator-if-unforced! s #f)
|
||||
(set-lazily-created-stream-thunk-or-stream! s v)
|
||||
(if (null? dep-ses)
|
||||
v
|
||||
(loop s dep-ses))]
|
||||
[else
|
||||
(define who (lazily-created-stream-creator-if-unforced s))
|
||||
(if (symbol? who)
|
||||
(raise-arguments-error
|
||||
who
|
||||
"delayed expression produced a non-stream"
|
||||
"result" v)
|
||||
(raise-arguments-error
|
||||
'stream-cons
|
||||
"rest expression produced a non-stream"
|
||||
"rest result" v))])]))]
|
||||
[(for:stream? s) s]
|
||||
[else (raise-argument-error 'stream-force "stream?" s)]))
|
||||
|
||||
|
@ -122,10 +128,10 @@
|
|||
(syntax-rules ()
|
||||
((stream-cons obj strm)
|
||||
(eagerly-created-stream #f (lambda () obj)
|
||||
(lazily-created-stream (mcons #t (lambda () strm)))))
|
||||
(lazily-created-stream #t (lambda () strm))))
|
||||
((stream-cons #:eager obj strm)
|
||||
(eagerly-created-stream #t obj
|
||||
(lazily-created-stream (mcons #t (lambda () strm)))))
|
||||
(lazily-created-stream #t (lambda () strm))))
|
||||
((stream-cons obj #:eager strm)
|
||||
(eagerly-created-stream #f (lambda () obj)
|
||||
(stream-assert strm)))
|
||||
|
@ -150,4 +156,4 @@
|
|||
(eagerly-created-stream-rest v)
|
||||
(for:stream-rest v))))
|
||||
|
||||
(define stream-null (lazily-created-stream (mcons #f '())))
|
||||
(define stream-null (lazily-created-stream #f '()))
|
||||
|
|
Loading…
Reference in New Issue
Block a user