Partial Application and Currying in C# – Clearing the Fog

Partial Application vs. Currying

Most of the examples you’ll see on the regarding partial application and currying (even in F#) often talk about simple functions that take two parameters.  This is sort of pointless because when you partially apply one parameter or curry one parameter, the call to resolve the operation is identical, so you really don’t get an appreciation of the syntactical difference.  I, however, will avoid that by demonstrating the differences between partial application and currying using three (wow!) parameters.

Partial Application

Very simply, partial application lets you assign the first n parameters, returning a function that takes the rest.  Given a function that returns the sum of three values:

Func<int, int, int, int> add = (a, b, c) => a + b + c;

You can partially apply one or two parameters:

Func<int, int, int> needsTwoMoreParams = (b, c) => add(3, b, c);
Func<int, int> needsOneMoreParam = (c) => add(3, 4, c);

Using these functions looks like this:

int twelve = needsTwoMoreParams(4, 5); 
twelve = needsOneMoreParam(5);

Notice we have to explicitly define the return type of the partial application function.  We cannot use var!

var needsOneParam = (b, c) => add(3, b, c);

Cannot assign lambda expression to an implicit-typed variable.

In a functional programming language like F#, the type is inferred:

> let add a b c = a + b + c;;
val add : a:int -> b:int -> c:int -> int

> let add3 = add 3;;
val add3 : (int -> int -> int)

> let add3and4 = add 3 4;;
val add3and4 : (int -> int)

The key thing to note with partial application in C# is the construct (b, c) for the remaining parameters in the needsTwoMoreParams function.  This is what tells you it’s a partial application rather than currying!

You can do the same thing with functions that are not C# Func types but Action types:

Action<int, int, int> xadd = (a, b, c) => Console.WriteLine(a + b + c);
Action<int, int> xoneParam = (b, c) => add(3, b, c);
Action<int> xtwoParams = (c) => add(3, 4, c);


As Jon Skeet so eloquently wrote: “currying effectively decomposes the function into functions taking a single parameter.”  Study this example carefully:

Func<int, Func<int, Func<int, int>>> curried = a => b => c => a + b + c;
int twelve = curried(3)(4)(5);
Func<int, Func<int, int>> oneParam = curried(3);
Func<int, int> twoParams = curried(3)(4);
twelve = twoParams(5);

Note how the parameters of the curried function are called as separate parameters: (3)(4)(5).  Also note that the function is defined with a => b
=> c=>
, which tells you this is a curried function!

Interestingly, we can use var in this case:

var oneParam = curried(3);
var twoParams = curried(3)(4);

Again however, the syntax in C# for defining the curried function must be explicit – “a function that takes an int that returns a function that takes an int and returns a function that takes an int and returns an int.”  This gets ugly real quick, and again, in F#, the inference engine knows you’re doing currying:

> add(3);;
val it : (int -> int -> int) = <fun:it@9>

> let add3 = add(3);;
val add3 : (int -> int -> int)

> let add3and4 = add(3)(4);;
val add3and4 : (int -> int)

> add3and4(5);;
val it : int = 12

Also notice this in F#:

add3(4, 5);;
add3(4, 5);;

stdin(13,6): error FS0001: This expression was expected to have type
but here has type
''a * 'b'

The correct syntax, in F# looks just like C# – one parameter per “function”:

> add3(4)(5);;
val it : int = 12

Again, once you create a curried function, you have to treat it like a curried function, same as in C#.

What about curried functions of an Action?  It would look like this:

Func<int, Func<int, Action<int>>> curried = a => b => c => Console.WriteLine(a + b + c);
var oneParam = curried(3);
var twoParams = curried(3)(4);
twoParams(5);  // prints 12

Note how the final result of last Func is an Action that takes the last value.

So now hopefully you have a clear understanding of the difference between partial application and currying.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s