← back to programming

Streams

Abelson & Sussman · 1996 · SICP §3.5

Delayed evaluation lets you work with infinite sequences. Streams are lazy lists: cons-stream delays the cdr. You get the modularity of sequences without the cost of computing everything upfront.

1 force 2 force 3 force ... promise Each cdr is a promise — computed only when forced

Streams are delayed lists

cons-stream pairs a value with a promise to compute the rest. stream-car returns the value; stream-cdr forces the promise. Only the elements you actually request get computed.

Scheme

Infinite streams

Since the cdr is delayed, a stream can be infinite. The integers, the Fibonacci sequence, and the primes all have natural stream definitions.

Scheme

Exploiting the stream paradigm

Stream-map, stream-filter, and stream-accumulate give you the same composable pipeline as list operations, but lazily. Define a sieve of Eratosthenes in two lines.

Scheme

Implicit stream definitions

Streams can be defined implicitly, referring to themselves. The ones stream is 1 followed by itself. Adding two streams element-wise lets you define Fibonacci numbers as: fibs = 0, 1, fibs + (cdr fibs).

Scheme

Streams and delayed evaluation

Streams decouple the order of events from the apparent structure of the computation. You write code that looks like it processes an entire sequence, but only the needed elements are ever computed. This is normal-order evaluation achieved within an applicative-order language.

Scheme

Notation reference

Scheme Python Meaning
(cons-stream a b)yield aPair value with delayed rest
(stream-car s)next(s)Get current element
(stream-cdr s)(implicit in next)Force the promise, get rest
(delay expr)lambda: exprWrap expression as promise
(force promise)promise()Evaluate a delayed expression

Translation notes

Neighbors
Ready for the real thing? Read SICP §3.5.