Chain iterators together and the laziness composes. Nothing in the chain does work until the end of the chain is pulled — and it pulls only as much as it needs.
C#
var firstBig = Naturals()
.Where(n => n % 7 == 0)
.Select(n => n * n)
.First(n => n > 1000);
Console.WriteLine(firstBig); // 35 * 35
Output
1225
Where and Select are iterators too — that is why LINQ behaves this way. The whole chain
produced exactly as many values as it took to satisfy First, and then stopped mid-stream.
An eager version would have built three lists, two of them infinite.
The same answer, two costs
Eager — computes everything
C#
var all = new List<int>();
for (int i = 1; i <= 1000000; i++)
all.Add(i);
var sevens = new List<int>();
foreach (var n in all)
if (n % 7 == 0) sevens.Add(n);
var squares = new List<int>();
foreach (var n in sevens)
squares.Add(n * n);
var answer = squares.First(n => n > 1000);Lazy — computes 33 values
C#
var answer = Naturals()
.Where(n => n % 7 == 0)
.Select(n => n * n)
.First(n => n > 1000);Three million operations against thirty-five. And the lazy version does not need to guess an upper bound of a million — a guess that is either wasteful or wrong.
Try it: Task 2
Open the editorTry it: Task 3
Open the editor