Proper Currying in C#

Viewed 24050

Given a method DoSomething that takes a (parameterless) function and handles it in some way. Is there a better way to create the "overloads" for functions with parameters than the snippet below?

public static TResult DoSomething<TResult>(Func<TResult> func)
{
    //call func() and do something else
}

public static TResult DoSomething<T0, TResult>(
    Func<T0, TResult> func,
    T0 arg0)
{
    return DoSomething(() => func(arg0));
}

public static TResult DoSomething<T0, T1, TResult>(
    Func<T0, T1, TResult> func,
    T0 arg0, T1 arg1)
{
    return DoSomething(arg => func(arg, arg1), arg0);
}

public static TResult DoSomething<T0, T1, T2, TResult>(
    Func<T0, T1, T2, TResult> func,
    T0 arg0, T1 arg1, T2 arg2)
{
    return DoSomething(arg => func(arg, arg1, arg2), arg0);
}
3 Answers

EDIT: As noted in comments, this is partial application rather than currying. I wrote a blog post on my understanding of the difference, which folks may find interesting.

Well, it's not particularly different - but I'd separate out the currying part from the "calling DoSomething" part:

public static Func<TResult> Apply<TResult, TArg> (Func<TArg, TResult> func, TArg arg)
{
    return () => func(arg);
}

public static Func<TResult> Apply<TResult, TArg1, TArg2> (Func<TArg1, TArg2, TResult> func,
                                                          TArg1 arg1, TArg2 arg2)
{
    return () => func(arg1, arg2);
}

// etc

Then:

DoSomething(Apply(foo, 1));

That way you can reuse the currying code in other situations - including cases where you don't want to call the newly-returned delegate immediately. (You might want to curry it more later on, for example.)

The @Jon Skeet answer is right, but write by hand all possibles overload is something insane, so you can use a lib like Curryfy that do this job for you. Curryfy lib particularly exposes Curry, UnCurry and ApplyPartial extension methods, with a lot of overloads.

Here is the method that allows to write unlimited calls of functions using dynamic (like Curry in js):

dynamic Sum(int a)
{
    Console.WriteLine(a);
    return new Func<int, dynamic>(b => Sum(a + b));
}

If you call it like this Sum(2)(3)(4)(10) the output will be:

2
5
9
19
Related