Fold - 7 higher order functions
This is the second blog post in a series about higher order functions. Fold is one of my most commonly used higher order function.
Fold
Fold lets you run an aggregate function over the items in a list to return an aggregated result. This is extremely useful in many scenarios where you wouldn't even think about it. This function already exists in the .NET Framework as part of LINQ, called Aggregate.
Examples
In this example we have a couple of cats from the database and we would like to aggregate their ages. We could map out their age to a list, and then run sum, but that would be traversing the list twice. Using fold is more appropriate here.
cats.Fold((acc, cat) => acc + cat.Age, 0); // => 24
Here's another less trivial example. Let's say we have a sequence that should be transformed to an array. Sure, the LINQ framework already has this functionality, but it would be interesting to investigate how we could accomplish this with Fold.
return newArray;
}
var list = new List<int> { 1, 2, 3 }; list.Fold(GrowArray, new int[0]); // => [1, 2, 3]
Disclaimer: Don't do this at home. List already has a ToArray function. This was made to illustrate an example with Fold.
Implementation
The implementation of the fold function is pretty straight forward.
if (list == null)
{
throw new ArgumentNullException("list", "Supplied list to Fold is not allowed to be null");
}
var result = init;
foreach (var item in list)
{
result = fn(result, item);
}
return result;
}
public static U Fold<T, U>(this IEnumerable<T> list, Func<U, T, U> fn, U init) { return Fold(fn, list, init); }
Loop through the list and accumulate an result.
Conclusion
Both map and fold can take you far, writing code that is easy to test and read by extracting essential logic into their own functions. I've seen so many foreach accumulate code snippets that would be a fold one liner in my days, and I hope this will help anyone to shorten their code and clarify its purpose.