A FUNCTIONAL APPROACH TO ITERATORS

An iterator function can be generic, which is an approach that most of LINQ functions use to work with arbitrary types. Using the ideas of higher order functions, then, a very flexible function to create sequences can be constructed:

public static IEnumerable<T> Sequence<T>(Func<T, T> getNext,

  T startVal, Func<T, bool> endReached) {

  if (getNext == null)

    yield break;

  yield return startVal;

  T val = startVal;

  while (endReached == null || !endReached(val)) {

    val = getNext(val);

    yield return val;

  }

}

Take your time to read through the Sequence function; it’s not really complicated. (If you need a reminder on how exactly iterators work, you can find that information back in Chapter 5.)

With the introduction of iterators in C# 2.0, Microsoft made the important move from the classes that are needed to implement the .NET iteration interfaces to functions, which are a much more natural context for functionality that iterates over data according to some algorithm. Creating a higher order function that externalizes important parts of the algorithm is an obvious next step, and that’s what the Sequence function represents. As a result, it is now easy to create arbitrary sequences using function calls:

var oddNumbersFrom1To19 =

  Functional.Sequence(x => x + 2, 1, x => x >= 19);

 

var squares =

  Functional.Sequence(x => x * x, 2, x => x >= 10000);

 

var fibonacci =

  Functional.Sequence(

    x => x.Item2 == 0 ? Tuple.Create(0, 1) ...

Get Functional Programming in C#: Classic Programming Techniques for Modern Projects now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.