Next: , Up: streams   [Index]


1.15.1 Basic interface

The basic API provides two mutually–recursive abstract data types: An object of the ‘stream’ abstract data type is a promise that, when forced, is either ‘stream-null’ or is an object of type ‘stream-pair’. An object of the ‘stream-pair’ abstract data type contains a kar and a kdr, which must be a ‘stream’. The essential feature of streams is the systematic suspensions of the recursive promises between the two data types.

alpha stream
  :: (promise stream-null)
  |  (promise (alpha stream-pair))

alpha stream-pair
  :: (promise alpha) x (promise (alpha stream))

The object stored in the kar of a ‘stream-pair’ is a promise that is forced the first time the kar is accessed; its value is cached in case it is needed again. The object may have any type, and different stream elements may have different types. If the kar is never accessed, the object stored there is never evaluated. Likewise, the kdr is a promise to return a stream, and is only forced on demand.

This API provides eight operators: constructors for ‘stream-null’ and ‘stream-pair’, type recognisers for streams and the two kinds of streams, accessors for both fields of a ‘stream-pair’, a lambda that creates procedures that return streams.

Constant: stream-null

Return a promise that, when forced, is a single object, distinguishable from all other objects, that represents the null stream. stream-null is immutable and unique.

Syntax: stream-cons obj stream

Accept an object and a stream and create a newly–allocated stream containing a promise that, when forced, is a ‘stream-pair’ with the object in its kar and the stream in its stream-cdr.

Once created, a ‘stream-pair’ is immutable; there is no stream-set-kar! or stream-set-kdr! that modifies an existing ‘stream-pair’. There is no dotted–pair or improper stream as with lists.

Function: stream? obj

Return #t if obj is a ‘stream’ and #f otherwise. If obj is a ‘stream’, stream? does not force its promise.

If (stream? obj) is #t, then one of (stream-null? obj) and (stream-pair? obj) will be #t and the other will be #f; if (stream? obj) is #f, both (stream-null? obj) and (stream-pair? obj) will be #f.

Function: stream-null? obj

Return #t if the obj is the distinguished null stream and #f otherwise. If obj is a ‘stream’, stream-null? must force its promise in order to distinguish ‘stream-null’ from ‘stream-pair’.

Function: stream-pair? obj

Take an obj and return #t if it is a ‘stream-pair’ constructed by stream-cons and #f otherwise. If obj is a ‘stream’, stream-pair? must force its promise in order to distinguish ‘stream-null’ from ‘stream-pair’.

Function: stream-car stream

Return the object stored in the kar of stream. stream-car signals an error if the object passed to it is not a ‘stream-pair’. Calling stream-car causes the object stored there to be evaluated if it has not yet been; the object’s value is cached in case it is needed again.

Function: stream-cdr stream

Return the stream stored in the kdr of stream. stream-cdr signals an error if the object passed to it is not a ‘stream-pair’. Calling stream-cdr does not force the promise containing the stream stored in the kdr of the stream.

Syntax: stream-lambda formals . body

Create a procedure that returns a promise to evaluate the body of the procedure. The last body expression to be evaluated must yield a stream.

As with normal lambda, formals may be a single variable name, in which case all the formal arguments are collected into a single list, or a list of variable names, which may be null if there are no arguments, proper if there are an exact number of arguments, or dotted if a fixed number of arguments is to be followed by zero or more arguments collected into a list.

body must contain at least one expression, and may contain internal definitions preceding any expressions to be evaluated.

Examples:

(define strm123
  (stream-cons 1
    (stream-cons 2
      (stream-cons 3
        stream-null))))

(stream-car strm123)
⇒ 1

(stream-car (stream-cdr strm123))
⇒ 2

(stream-pair?
  (stream-cdr
    (stream-cons (/ 1 0) stream-null)))
⇒ #f

(stream? (list 1 2 3))
⇒ #f

(define iter
  (stream-lambda (f x)
    (stream-cons x (iter f (f x)))))

(define nats
  (iter (lambda (x)
          (+ x 1))
        0))

(stream-car (stream-cdr nats))
⇒ 1

(define stream-add
  (stream-lambda (s1 s2)
    (stream-cons
      (+ (stream-car s1) (stream-car s2))
      (stream-add (stream-cdr s1)
                  (stream-cdr s2)))))

(define evens
  (stream-add nats nats))

(stream-car evens)
⇒ 0

(stream-car (stream-cdr evens))
⇒ 2

(stream-car (stream-cdr (stream-cdr evens)))
⇒ 4

Next: , Up: streams   [Index]