One of the most powerful techniques I saw during our Scheme lessons was the ability to pass (and create) functions using lambda expressions. In Scheme (a LISP dialect…), procedures are treated as ‘first class objects’, a quick example:
>>> (define (map proc a-list)
(cond
((null? a-list) ‘())
(else
(cons (proc (car a-list))
(map proc (cdr a-list))))))
>>> (map (lambda (x) (* x 3))
(list 1 2 3 4 5))
(3 6 9 12 15)
We’ve declared a procedure map which will take every element of our list and apply the function ‘proc’ to each element of this list. Then we call our ‘map’ function on a list with the lambda expression (x) => x * 3 as the argument (that’s right, a function as an argument…).
I was curious if something like this could be done in C#, first I looked into delegates but I discovered the new C# 3.0 specification contains ‘lambda expressions’, or ‘anonymous methods’ in .NET 1.1. Here’s the Scheme example translated into C# 3.0 (using Visual Studio 2008 beta 2) with the lamda expression in the builtin generic Func type:
class Program
{
static List
MapOverCollection(ICollection collection, Func func)
{
//We’ll pass the results as a list which we instantiate here
List result = new List();
foreach (T el in collection)
//Apply our lambda expression to each element in the ICollection
//and add it to our result list…
result.Add(func(el));
return result;
}
static void Main(string[] args)
{
//Declare a simple list with some elements
List testList = new List();
testList.Add(1);
testList.Add(2);
testList.Add(3);
testList.Add(4);
testList.Add(5);
//Print our list to check it’s contents
PrintList(testList);
//Apply our lambda expression to each element of the list
//using our generic method.
List mappedList = MapOverCollection(testList, i => i * 3 );
//Print the result list.
PrintList(mappedList);
Console.Read();
}
static void PrintList(List list)
{
Console.Write(”(”);
foreach (T el in list)
Console.Write(” ” + el.ToString() + ” “);
Console.Write(”)\n”);
}
}
The output is the same! Now you might ask: “Why should we use this?”. Well, seems like Msft. has included an armada of selectors which take predicates (for instance x => x > 5) as arguments, a small example of this is the where method on an IEnumerable:
IEnumerable overFive = someNumbers.Where(i => i > 5);
This will make a new IEnumerable which contains all elements of the someNumbers IEnumerable that are larger than 5. Offcourse you can also apply this kind of logic on your own classes (Person, Download, …) or other builtin classes (strings, listviewitems, …).
To finish this post I’d like to show an alternative way of event handling using the lambda expressions. Suppose you’d want to popup some text when a user clicks a button, normally you’d attach event handlers and implements the appropriate methods. Now you could use lambda expression, like this:
btnLambdaButton.Click += (sender, args) => MessageBox.Show(”Clicked”);
We attach an eventhandler using the += operator, we create a lambda expression with the two (not possible in normal lambda calculus) usual arguments for an event (it’s sender and the eventargs) and after the lambda operator (=>), we say what should be done… That’s it!
These lambda expressions don’t make life easier for the average developer, but once you get the hang of it I’m sure it’s a superb tool for every coder. Offcourse one can argue that lambda expressions don’t belong in an OO language such as C# but that such academic features should remaing solely in functional languages (such as Scheme). But if you don’t like it, nothing is stoppig you from shoving it in the closet!