Sequences is a port of Scala's Stream[+A] to C#.
Sequences is available on NuGet and the source code is on GitHub
A Sequence T is an immutable lazy list whose elements are only evaluated when they are needed. A sequence is composed by a head (the first element) and a lazily-evaluated tail (the remaining elements).
The fact that the tail is lazily-evaluated, makes it easy to represent infinite series or sets. For example, here's how to represent the set of all natural numbers.
public ISequence<int> Naturals(int start) { return new Sequence<int>( head: start, tail: () => Naturals(start + 1)); } var naturals = Naturals(1); //take the first 5 natural numbers naturals.Take(5).ForEach(Console.Write); //prints 12345
Or, even simpler:
var naturals = Sequence.From(1);
Sequences also features memoization, i.e., the sequence stores previously computed values to avoid re-evaluation.
//start with number 1, and then keep adding 2 to the previous number var odds = Sequence.Iterate(1, odd => { Console.WriteLine("Adding " + odd + " + 2"); return odd + 2; }); odds.Take(3).ForEach(Console.WriteLine); odds.Take(5).ForEach(Console.WriteLine); //prints //1 //Adding 1 + 2 //3 //Adding 3 + 2 //5 //and then //1 //3 //5 //Adding 5 + 2 //7 //Adding 7 + 2 //9
You can iterate through an infinite sequence for as long as you want. As long as you don't hold onto its head, each sequence will be elected for garbage collection as soon as you move to the next value. This prevents an infinite sequence from occupying a large and growing ammount of memory.
foreach (var odd in Sequence.Iterate(1, odd => odd + 2)) { //when you move to Sequence(11, ?), //the previous Sequence(9, ?) is elected for collection. }