Cigars, Lambda Expressions, and .NET - ' Closures and Currying ' (
Page 2 of 2 )
Understanding Closures
The basic nature of code is that function calls make software easy to write. Local variables are allocated on the call stack and this memory is cleaned up when the function returns. But, what happens if one creates a new dynamic type with an expression and that expression refers to a local variable? Well, by default the local variable is no longer valid. To solve this problem the new compiler will create a wrapper class, internally, called a closure. The wrapper class will contain any local variable references and the anonymous method (the Lambda Expression) that refers to the local variable.
ADVERTISEMENT
All of this plumbing is automatic, so you can write code like the following and not worry about a dangling reference or stack-cleaned variables.
Listing 2: This function refers to a local variable and returns what is effectively an anonymous method. The .NET 3.5 compiler will create a "closure", or wrapper class, that extends the life of the local variable and the Lambda Expression.
public static Func<int, int> MakeClosure()
{
int p = 5;
Func<int, int> func = s => s + p;
return func;
}
You can use local variables and return dynamic methods represented by Lambda Expressions without worry. The .NET compiler takes care of the plumbing for you.
Currying
I was presenting on "Orcas" at my local users group and someone asked me "do Lambda Expressions support currying?" I didn't know, and I wasn't sure I understand currying.
Currying, or Schönfinkelisation, is named after Haskel Curry but was invented by Schönfinkel and Frege. Currying is the process of turning a multi-argument method—a multiary function—into several single argument—singlary—methods.
Suppose for example we have a Lambda Expression
(x, y) => x * y;
a multiary function, which returns x multiplied by y. Currying entails turning this into a function that accepts x and returns an additional function that accepts y. In this way only one argument needs to be plugged in at a time. So, given a function with n arguments, currying means the first n-1 arguments return Lambda Expressions of only one argument and the last function returns the result.
To curry (x,y) => x*y we first create a function that accepts x, returning a function that only needs y (because we have x).
var a = Curry(10);
Console.WriteLine(a(34));
// returns a Lambda expression that takes one argument
static Func<int, int> Curry(int x)
{
Func<int, int, int> multiply = (y, z) => y * z;
return y => multiply(x,y);
}
In truth, I am not sure how everyday programmers will employ currying, but the literature says:
"If you fix some arguments, you get a function of the remaining arguments."
"In theoretical computer science, currying provides a way to study functions with multiple arguments in very simple theoretical models such as the Lambda Calculus in which functions only take a single argument."
I am still wondering what the day to day practical uses of currying are. My best guess to date is that the ability to create methods that do just one thing and chain these things together to get a result will make it easier to write code generators. Instead of a multiary function that performs a lot of complex operations, singlary code generators return n-1 new functions and the nth function finishes the task. Again, this is my best guess.
Lambda Expressions look terse, but if you understand that they are very condensed anonymous methods then they aren't as challenging to understand. Words like closures and currying again muddy the waters, but closures are wrapper methods for local variables used in Lambda Expressions that go out of scope and currying converts functions that do a lot with a lot of arguments into several Lambda Expressions that each just do a part. Closures are automatic and most pedestrian programming tasks won't require currying.
So why do we need Lamda Expressions? The answer is that less code has to do more for the same reason we need multi-core processors. Writing code takes time. If less code does more work then we can do more complicated things with relatively the same amount of workload. (No one wants to work more, right?!)
LINQ and supporting Lambda Expressions are going to show up everywhere. Work with Orcas for a few hours, and if you love bit twiddling then you will love Orcas.
Paul Kimmel is an architect for TriState Hospital Supply Corporation and the co-founder of the Greater Lansing Area .NET Users Group (glugnet.org). Look for his new book UML DeMystified (McGraw-Hill/Osborne, October 2005) and his upcoming book C# Express for Professional Programmers (Addison-Wesley, Spring 2006).
If you have a programming question you can contact him at pkimmel@softconcepts.com.