I personally think stream-like data structures exist mainly to postpone the moment of real computation — data is only produced when truly needed. Incidentally, their existence also solves how computers describe ‘infinity’: as long as you can always fetch data from the data source, the source can be considered infinite.
Among stream processing applications, the algorithm that impressed me deeply is the prime sieve problem — defined recursively and implemented quite concisely.
I suggest understanding car and cdr before reading this.
Stream Basics
1 | ; streams are used like cons, car, cdr, but the implementation differs slightly |
Stream Implementation
From the example above, in the stream implementation car and stream-car act identically; the difference between cdr and stream-cdr is one call to force — so we only need to define force properly.
1 | ; must be defined as a macro; interested readers can look here: https://stackoverflow.com/a/14641015/5563477 |
Some Stream Operations
The code below doesn’t consider that streams may end; real code should consider this problem.
The Stream of All Positive Integers
This stream has a property: each later item is 1 greater than the previous — so it can be defined recursively:
1 | (define (all-num n) |
Getting the Nth Element of a Stream
Just keep getting the stream’s next item until we obtain the element we want:
1 | (define (my-stream-ref n s) |
Operating on This Stream to Get a New Stream
For example, operating on the positive-integer stream to double every element can be done like this:
1 | (define (my-stream-map proc s) |
Filtering the Data in This Stream to Get a New Stream
For example, operating on the positive-integer stream to take only the odd numbers can be done like this:
1 | (define (my-filter-stream pred s) |
The Prime Sieve Algorithm
The following content comes from Wikipedia: https://zh.wikipedia.org/wiki/%E5%9F%83%E6%8B%89%E6%89%98%E6%96%AF%E7%89%B9%E5%B0%BC%E7%AD%9B%E6%B3%95


Simply put: once we obtain a prime, filter out all subsequent integers divisible by it; the sequence we get is then a sequence of primes. Written in scheme:
1 | (define (sieve s) |
This recursive implementation can be said to perfectly match the definition.
Summary
In SICP, when introducing streams the teacher viewed them from an electrical-engineering perspective: circuit signals fluctuate and are continuous; passing through different rectifiers they can undergo many changes yet remain continuous — this is a kind of stream.
Although our data-structures course never covered it, a stream is actually an extended data structure, and also a kind of control logic. When you represent certain data as a stream, it means other parts of the program must also adapt to this change. It postpones a piece of code’s real execution time, allowing data to be produced only when truly used.
Stream processing is a powerful tool; programs can be implemented entirely stream-style, but this brings one problem: you may have no idea when a function will be called. Therefore I personally think such data structures suit the interaction points between several parts of a program or between several programs — like between producer and consumer, especially for multi-level consumers: submitting each completed task effectively prevents downstream consumers from starving.
Appendix: JS Implementation
1 | // I won't fancily implement with lambda or dispatch — a two-element array is enough |