View the whole series:
In the previous post in this series we discussed currying and partial application with examples in two variables. We saw that with two variables partial application and currying look very similar. Currying just appears to have an extra step of creating the method that generates our partially applied methods, but this is actually somewhat deceptive. When going beyond two parameters we will start to see the differences in currying and partial application a little more clearly.
So, lets use a multiply method with a third parameter:
public static int Multiply(int a, int b, int c)
{
return a * b * c;
}
So, lets first look at an implementation of a Curry function with three arguments:
public static Func<TArg1, Func<TArg2, Func<TArg3, TResult>>>
Curry<TArg1, TArg2, TArg3, TResult>
(this Func<TArg1, TArg2, TArg3, TResult> func)
{
return argument1 => argument2 => argument3 =>
func(argument1, argument2, argument3);
}
You may already be seeing the differences here. With the currying method we are chaining these arguments together so that we build up new methods by passing in single arguments at a time. Here is how this would look when we used it:
Func<int, int, int, int> method = Multiply;
var curriedMultiply = method.Curry();
var multiplyByTwo = curriedMultiply(2);
var multiplyByTwoThenFive = multiplyByTwo(5);
var multiplyByTwoThenSix = multiplyByTwo(6);
int result1 = multiplyByTwoThenFive(10);
int result2 = multiplyByTwoThenSix(10);
You see what we are doing here? We have curried the method, then we build up our methods by calling our curried methods over and over but always with only one parameter! You can shorten it with a bit of somewhat confusing syntax:
Func<int, int, int, int> method = Multiply;
var curriedMultiply = method.Curry();
var multiplyByTwoThenFive = curriedMultiply(2)(5);
var multiplyByTwoThenSix = curriedMultiply(2)(6);
int result1 = multiplyByTwoThenFive(10);
int result2 = multiplyByTwoThenSix(10);
You may or may not find it hard to read, but we are just skipping the intermediate step by passing two parameters with the second one being passed to the return type. In this instance though you are bypassing the advantages of currying, which is the ability to slowly build up methods, and you might as well be using partial application. You’ll see why in a second.
So, before we look at an implementation of a three parameter "PartiallyApply" method let me just say that there is more than one. When you think about it that makes sense. With two parameters "partially applied" can mean only one thing, that we have passed in one parameter. Otherwise it would be "unapplied" or "fully applied". 🙂 With three parameters though we can have one parameter pre-applied or two. So, here is our three parameter "PartiallyApply" methods:
public static Func<TArg2, TArg3, TResult>
PartiallyApply<TArg1, TArg2, TArg3, TResult>
(this Func<TArg1, TArg2, TArg3, TResult> func, TArg1 argument1)
{
return (argument2, argument3) =>
func(argument1, argument2, argument3);
}
public static Func<TArg3, TResult>
PartiallyApply<TArg1, TArg2, TArg3, TResult>
(this Func<TArg1, TArg2, TArg3, TResult> func,
TArg1 argument1, TArg2 argument2)
{
return argument3 => func(argument1, argument2, argument3);
}
There you have it, a three parameter "PartiallyApply" method that has been partially applied in two different ways. Here you can see how we use them:
Func<int, int, int, int> method = Multiply;
var needTwoMoreParams = method.PartiallyApply(2);
var needOneMoreParam = method.PartiallyApply(2, 5);
int result1 = needTwoMoreParams(5, 3);
int result2 = needOneMoreParam(3);
So easy! So, now you see how currying and partial application are actually quite different concepts. Currying is useful if you need to slowly build up your function over several different iterations while partial application is useful if you just need to set a few parameters on a function and the rest will be filled in later. While you will probably be able to find a few places where partial application may be useful, currying will probably be a bit harder to find a real world use for. If you have any good examples of using these in the real world, please leave a comment!
Loved the article? Hated it? Didn’t even read it?
We’d love to hear from you.
It has been a great series. I finished reading this 9-part-series posts in one go without stopping while typing code on my VS 2010.
Hope to see more (actually i am also reading on your Ironruby series)
Keep up the great work!