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
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.