Functional programming in C# 3.0 and LINQ

I first learned about functional programming a few years ago when I took a class in Haskell programming at my university, Chalmers. While Haskell might not be for everyday use, many of the concepts are very compelling, such as higher order functions, pattern matching, lazy evaluation, list comprehensions, lambda functions and map/fold/filter. Over the years many mainstream programming languages have adopted a subset of those features. With the release of C# 3.0 Microsoft has brought some of this functionality to C#.

Lambda functions
A lambda function is simply an anonymous function that can contain expressions and statements. Lambda functions can be used to create delegates or expression trees. Lambda functions use the lambda operator => (read as “goes to”). On the left side the input parameters is defined and the right side holds the expressions or statements. A simple example would be:

(x, y) => x+y

But wait, where is the type declaration? The types does not have to be defined, the compiler will declare the types by using type interference at compile time, so everything is still strongly typed.

The framework defines a number of parameterized delegate types (the first type is the return type):

public delegate TR Func();
public delegate TR Func(T0 a0);
public delegate TR Func(T0 a0, T1 a1);
public delegate TR Func(T0 a0, T1 a1, T2 a2);
public delegate TR Func(T0 a0, T1 a1, T2 a2, T3 a3);

So we could define our function as follows:

Func fun = (x, y) => x + y; 

In functional programming it is very common to work with lists. Three very common computations are:

    1. Applying a function to every element of a list (map)
    2. Computing a value based on all elements in the list. For example the total sum of a list containing numeric values (fold)
    3. Selecting just a subset of the elements (filter)

In C# the equivalents are Select, Aggregate and Where. Here is a simple example of how they can be used:

var list = new int[] { 1, 2, 3, 4, 5 };
list.Aggregate(0, (total, val) => total += val); // returns 15, 0 is the initial value. 
list.Select(x => x + 1); // returns [2, 3, 4, 5, 6]
list.Where(x => x > 3); // returns [4, 5]

Using map/fold/filter instead of using regular loops makes it easier to understand and reason your code.


Leave a Reply

Your email address will not be published. Required fields are marked *