Streams

Data structures that can be used to model state . Streams provide a functional programming alternative to objects that can be efficient in some kinds of applications.

Specifically, streams model stateful objects that change over time as if the entire time series is one entity, i.e, it is a frozen view of a sequence by looking at the entire sequence at once. Practically, streams are implemented as lists, along with delayed evaluation to ensure element creation only as needed, making the data structure very efficient. In simple terms, it is a list of instantiated (so far) elements followed by a promise to instantiate more elements.

Scheme implementation:

(define (delay <exp>)
	(lambda () <exp>))

(define (force delayed-object)
	(delayed-object))

(define (cons-stream <a> <b>)
	(cons <a> (delay <b>)))

(define (stream-car stream) (car stream))

(define (stream-cdr stream) (force (cdr stream)))

Infinite streams

The cool thing about streams is that they can even be used to represent infinite sequences of all sorts, calculating the required elements on-demand. Ex: the fibonacci sequence, power series of ex, sin(x), time-varying signals, approximations of infinite sums (with accelerated convergence possible) etc

Streams can even be defined recursively, as long as the requisite number of elements are already instantiated at each stage. For example,

(define ones (cons-stream 1 ones))

defines a stream [1, 1, ....].

Complexities of delay

The delay functionality can (and must) also be used more generally to account for requisite delays in systems such as integrators, RLC circuits etc. However, explicit use of delay and force introduces additional complexities because processes must now be defined to have two classes of input arguments, delayed and non-delayed, and must be called appropriately.

One workaround to this would be to specify that all arguments are delayed, i.e, only evaluated when needed. This corresponds to the normal order of evaluation.


Links

Sources