Many functions expect an enumerable and return a list back. It means, while performing multiple operations with Enum, each operation is going to generate an intermediate list until we reach the result.

Streams support lazy operations as opposed to eager operations by enums. In short, streams are lazy, composable enumerables. What this means is Streams do not perform an operation unless it is absolutely needed.

Streams are composable, lazy enumerables (for an introduction on enumerables, see the Enum module). Any enumerable that generates elements one by one during enumeration is called a stream. For example, Elixir's Range is a stream:

iex> range = 1..5
iex> 1..5
iex> Enum.map(range, &(&1 * 2))
iex> [2, 4, 6, 8, 10]

In the example above, as we mapped over the range, the elements being enumerated were created one by one, during enumeration. The Stream module allows us to map the range, without triggering its enumeration:

iex> range = 1..3
iex> stream = Stream.map(range, &(&1 * 2))
iex> Enum.map(stream, &(&1 + 1))
iex> [3, 5, 7]