What is Curry in C#?
Currying a method call breaks the single method into a chain of methods. Let's start with the very simple method transformation as an example of what we will be doing. If we have a method defined with one input and one output as follows
Func<Int32, Int32> SubtractOne = x => x - 1;
We can call this normally as
Func<Int32, Int32> SubtractOne = x => x - 1;
Int32 result = SubtractOne(8);
If the method was transformed to return a delegate with a single input parameter, we would be able to call it a bit differently
Func<Int32, Func<Int32, Int32>> SubtractOne = x => y => x - y;
Int32 result = SubtractOne(8)(8);
How do we build our simplified Curry() method transformation?
It's a very simple utility method that we can use to modify any type of function with one argument that will return a delegate.
public static Func<TInput1, TOutput> Curry<TInput1, TOutput>(this Func<TInput1, TOutput> f)
{
return x => f(x);
}
Pretty simple concept... right? In reality, we probably wouldn't really curry a function with only one input parameter because the whole point is to get the arguments down to one tastey argument per delegate "call", but hopefully this sample helps you understand how we will begin to spice up our methods with curry.
Ultimately we would like to be able to curry a method with multiple input parameters as follows.
Func<Int32, Int32, Int32, Int32, Int32> Add = (w, x, y, z) => w + x + y + z;
Console.WriteLine(Add(1, 2, 3, 4)); // Normal call
Console.WriteLine(Add.Curry()(1)(2)(3)(4)); // Curried Call
We just need a library of utility methods that curry (and uncurry) multi-argument methods. All the samples are in the code accompanying this article, but here is the Curry() method for the 4-argument input method. At first, it's kind of painful to look at, but if you look at the other Curry() methods in the accompanying code. it should be pretty much self-explanatory. On the "outer shell" we have a delegate that takes a single input and returns another delegate (which takes a single input and returns another delegate... (and so on... and so on...)). So as a result we esentially have 4 "nested" delegates.
public static Func<TInput1, Func<TInput2, Func<TInput3, Func<TInput4, TOutput>>>>
Curry<TInput1, TInput2, TInput3, TInput4, TOutput>(
this Func<TInput1, TInput2, TInput3, TInput4, TOutput> f)
{
return w => x => y => z => f(w, x, y, z);
}
Why the heck would you want to do that?
Using this currying technique gives us a different syntax more conducive to building up a library of complex composite functions from simpler functions. For a (very(very)) simple example... if we wanted a function that computed the cubic area of a box, we could construct it from a simpler "Multiply" function as follows.
Func<Int32, Int32, Int32> Multiply = (x, y) => x * y;
Func<Int32, Int32, Int32, Int32> CubicArea = (length, width, height) =>
Multiply.Curry()(Multiply(length, width))(height);
Console.WriteLine("The cubic area is: " + CubicArea(2, 3, 4).ToString());
We could also use currying to reduce the number of input parameters. For example, if we wanted to find the cubic area of a perfectly square cube we could use currying to combine the input parameters.
Func<Int32, Int32> PerfectCubeArea = (length) =>
Multiply.Curry()(Multiply(length, length))(length);
As you can see, currying is really nothing more than a different syntax for calling our already existing methods. However, this powerful technique becomes more and more useful when we get into complex computations and want to build functionality from a composite tree perspective.
I hope you enjoy currying up your C# methods (which are especially tastey with coconut milk and shrimp).
Until next time,
Happy coding