Greg Beech's Website

Function currying in C#

C# does not automatically curry functions, so a function that multiplies two doubles together and returns the result must be assigned to a delegate that takes two arguments and returns a result:

Func<double, double, double> multiply = (a, b) => a * b;

This seems reasonable, but unfortunately it means that if we want to define a partial application of the function where one argument is already supplied (for example we might want to create a function that calculates the circumference of a circle from its diameter by supplying Math.PI) then we can't do it directly. Attempting to write the following statement gives the compiler error "Delegate 'Func' does not take '1' arguments":

var circumferenceFromDiameter = multiply(Math.PI);      // hopefully type Func<double, double>

What we actually want to achieve is a function that takes a double and returns a function that takes another double and returns the result of the two multiplied together. It is possible to write this in C#, but you have to change the function declaration from the intuitive 'two arguments goes to one result' syntax to somewhat harder to grasp nested lambda expression syntax. This is shown below with annotated type information so you can see what's going on (although I actually think the type information is more of a distraction than a help).

Func<double, Func<double, double>> multiply = a => b => a * b;
var circumferenceFromDiameter = multiply(Math.PI);      // type Func<double, double>
var circumference = circumferenceFromDiameter(10.0);    // type double

What would be useful are some methods for the Func<> class that could perform the currying for us, and fortunately as it's a mechanical translation these are quite easy to write. Shown below are extension methods for the 2, 3 and 4 argument versions of Func<>; there isn't one for the single argument version as this is already in curried form.

public static class Func
{
    public static Func<T1, Func<T2, TResult>> Curry<T1, T2, TResult>(
        this Func<T1, T2, TResult> func)
    {
        return arg1 => arg2 => func(arg1, arg2);
    }

    public static Func<T1, Func<T2, Func<T3, TResult>>> Curry<T1, T2, T3, TResult>(
        this Func<T1, T2, T3, TResult> func)
    {
        return arg1 => arg2 => arg3 => func(arg1, arg2, arg3);
    }

    public static Func<T1, Func<T2, Func<T3, Func<T4, TResult>>>> Curry<T1, T2, T3, T4, TResult>(
        this Func<T1, T2, T3, T4, TResult> func)
    {
        return arg1 => arg2 => arg3 => arg4 => func(arg1, arg2, arg3, arg4);
    }
}

We can now write the initial multiply expression as we'd prefer, and still be able to partially apply the function. It does take an extra line because you can't directly apply the extension method to the lambda expression without specifying that it is typed as a Func<>, and to do that in a single line results in a lot of ugly casting syntax.

Func<double, double, double> multiply = (a, b) => a * b;
var multiplyBy = multiply.Curry();                      // type Func<double, Func<double, double>>
var circumferenceFromDiameter = multiplyBy(Math.PI);    // type Func<double, double>
var circumference = circumferenceFromDiameter(10.0);    // type double

Note that this approach doesn't just facilitate writing local lambda expressions in a simpler way, it also allows you to partially apply library methods that you don't have control over the signature of by assigning them to an appropriate Func<> and then currying it. It's not ideal because you have to add syntactic noise to do the currying manually, but it's better than not being able to do it at all.

Just for fun, here's all you have to do to get the above scenario working in F#. We don't need to manually curry the methods as it is done automatically. There's also a lot less syntactic noise because F# doesn't require you to declare the concrete type of lambda expressions; it performs type checking based on what parameter type they take and what they return which makes a lot more sense than the C# approach - if you've ever come across the Predicate<T> != Func<T, bool> paradox then you'll know what I mean.

let multiply (a:double) b = a * b                   // type double -> double -> double
let circumferenceFromDiameter = multiply Math.PI    // type double -> double
let circumference = circumferenceFromDiameter 10.0

Posted Sep 16 2008, 08:36 AM by Greg Beech

Add a Comment

(required)  
(optional)
(required)  
Remember Me?

Enter the numbers above:
Copyright (C) Greg Beech. All rights reserved.
Powered by Community Server (Non-Commercial Edition), by Telligent Systems