ELIXIR / CHAPTER 08

Lazy enumeration and bounded demand

Advanced

Avoid materializing work the consumer never needs.

By the end of this chapter

  • Distinguish Enum from Stream timing
  • Bound an unbounded producer before collection
  • Keep side effects and repeated traversal explicit

The idea

Enum operations consume their input immediately and return results, while many Stream operations describe a lazy traversal. The lazy pipeline runs when a consumer enumerates it. This lets a program process large inputs incrementally or take a finite prefix from an unbounded source. Laziness does not mean the results are cached for future traversals.

Place limits before eager materialization. A pipeline that converts an infinite stream into a list before taking ten values never reaches the limiting step. Repeated enumeration can repeat callbacks and side effects, so keep transformations pure when the stream is intended to be reusable. Resource-backed streams also need a cleanup policy for normal completion and early termination.

Elixir example
result = Stream.iterate(1, &(&1 + 1))
  |> Stream.filter(&(rem(&1, 2) == 0))
  |> Stream.map(&(&1 * 3))
  |> Enum.take(3)
IO.inspect(result)
Result
[6, 12, 18]

The consumer demands only three transformed even values, keeping the otherwise infinite producer bounded.

Try it yourself

Take the first five valid records from a lazy source without reading the rest unnecessarily.

Use your own editor for this exercise. Runnable challenges on CodeQuest are available for JavaScript, Python, and SQL.

CHECK YOUR UNDERSTANDING

Chapter checkpoint

Which operation actually consumes a lazy pipeline here?