SRFI 40: A Library of Streams
A Chicken implementation of SRFI 40.[constant] stream-null
stream-null is the distinguished nil stream, a single Scheme object distinguishable from all other objects. If the last stream-pair in a stream contains stream-null in its cdr field, the stream is finite and has a computable length. However, there is no need for streams to terminate.
stream-null => (stream)[procedure] (stream-cons object stream)
stream-cons is the primitive constructor of streams, returning a stream with the given object in its car field and the given stream in its cdr field. The stream returned by stream-cons must be different (in the sense of eqv?) from every other Scheme object. The object may be of any type, and there is no requirement that successive elements of a stream be of the same type, although it is common for them to be. It is an error if the second argument of stream-cons is not a stream.
(stream-cons 'a stream-null) => (stream 'a) (stream-cons 'a (stream 'b 'c 'd)) => (stream 'a 'b 'c 'd) (stream-cons "a" (stream 'b 'c)) => (stream "a" 'b 'c) (stream-cons 'a 3) => error (stream-cons (stream 'a 'b) (stream 'c)) => (stream (stream 'a 'b) 'c)[procedure] (stream? object)
stream? returns #t if the object is a stream, and otherwise returns #f. A stream object may be either the null stream or a stream pair created by stream-cons.
(stream? stream-null) => #t (stream? (stream-cons 'a stream-null)) => #t (stream? 3) => #f[procedure] (stream-null? object)
stream-null? returns #t if the object is the distinguished nil stream, and otherwise returns #f
(stream-null? stream-null) => #t (stream-null? (stream-cons 'a stream-null)) => #f (stream-null? 3) => #f[procedure] (stream-pair? object)
stream-pair? returns #t if the object is a stream pair created by stream-cons, and otherwise returns #f.
(stream-pair? stream-null) => #f (stream-pair? (stream-cons 'a stream-null)) => #t (stream-pair? 3) => #f[procedure] (stream-car stream)
stream-car returns the object in the stream-car field of a stream-pair. It is an error to attempt to evaluate the stream-car of stream-null.
(stream-car (stream 'a 'b 'c)) => a (stream-car stream-null) => error (stream-car 3) => error[procedure] (stream-cdr stream)
stream-cdr returns the stream in the stream-cdr field of a stream-pair. It is an error to attempt to evaluate the stream-cdr of stream-null.
(stream-cdr (stream 'a 'b 'c)) => (stream 'b 'c) (stream-cdr stream-null) => error (stream-cdr 3) => error[procedure] (stream-delay expression)
stream-delay is the essential mechanism for operating on streams, taking an expression and returning a delayed form of the expression that can be asked at some future point to evaluate the expression and return the resulting value. The action of stream-delay is analogous to the action of delay, but it is specific to the stream data type, returning a stream instead of a promise; no corresponding stream-force is required, because each of the stream functions performs the force implicitly.
(define from0 (let loop ((x 0)) (stream-delay (stream-cons x (loop (+ x 1)))))) from0 => (stream 0 1 2 3 4 5 6 ...)[procedure] (stream object ...)
stream returns a newly allocated finite stream of its arguments, in order.
(stream 'a (+ 3 4) 'c) => (stream 'a 7 'c) (stream) => stream-null[procedure] (stream-unfoldn generator seed n)
stream-unfoldn returns n streams whose contents are produced by successive calls to generator, which takes the current seed as an arguments and returns n + 1 values:
(proc seed) -> seed result0 ... resultN
where resultI indicates how to produce the next element of the Ith result stream:
- value is the next car of this result stream
- no new information for this result stream
- the end of this result stream has been reached
Note that getting the next element in any particular result stream may require multiple calls to generator.
(define (take5 s) (stream-unfoldn (lambda (x) (let ((n (car x)) (s (cdr x))) (if (zero? n) (values 'dummy '()) (values (cons (- n 1) (stream-cdr s)) (list (stream-car s)))))) (cons 5 s) 1)) (take5 from0) => (stream 0 1 2 3 4)[procedure] (stream-map function stream ...)
stream-map creates a newly allocated stream built by applying function elementwise to the elements of the streams. The function must take as many arguments as there are streams and return a single value (not multiple values).
The stream returned by stream-map is finite if the given stream is finite, and infinite if the given stream is infinite.
If more than one stream is given, stream-map terminates when any of them terminate, or is infinite if all the streams are infinite. The stream elements are evaluated in order.
(stream-map (lambda (x) (+ x x)) from0) => (stream 0 2 4 6 8 10 ...) (stream-map + (stream 1 2 3) (stream 4 5 6)) => (stream 5 7 9) (stream-map (lambda (x) (expt x x)) (stream 1 2 3 4 5)) => (stream 1 4 27 256 3125)[procedure] (stream-for-each procedure stream ...)
stream-for-each applies procedure elementwise to the elements of the streams, calling the procedure for its side effects rather than for its values. The procedure must take as many arguments as there are streams. The value returned by stream-for-each is unspecified. The stream elements are visited in order.
(stream-for-each display from0) => no value, prints 01234 ...[procedure] (stream-filter predicate? stream)
stream-filter applies predicate? to each element of stream and creates a newly allocated stream consisting of those elements of the given stream for which predicate? returns a non-#f value. Elements of the output stream are in the same order as they were in the input stream, and are tested by predicate? in order.
(stream-filter odd? stream-null) => stream-null (take5 (stream-filter odd? from0)) => (stream 1 3 5 7 9)
For unclear reasons, the following procedures are also exposed:
make-s:promise make-stream make-box srfi-40:eager stream-error
These should probably not be used by programs.
Philip L. Bewig, ported to hygienic CHICKEN with test suite by Peter Danenberg