views:

1120

answers:

4

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);
}
+4  A: 

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

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

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

// etc

Then:

DoSomething(Curry(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.)

Jon Skeet
Why do you return Func<TResult> instead of Func<TResult, Func<Targ1, Targ2>> ?
Paco
Because Func<TResult> is what you want to be able to pass into DoSomething. The idea is that the Curry method should take a function which takes some parameters, as well as values for those parameters, and return a function which takes fewer parameters (0 in this case).
Jon Skeet
I thought the idea was that a Func<TResult, TArg1, Targ2> was should be converted to a function with less parameters Func<TResult, Func<Targ1, TArg2>>. You can create a default dosomething with a lot of parameters and curried variants
Paco
...with lesser parameters
Paco
But Func<TResult, Func<TArg1, TArg2>> is a function which *takes* a TResult and returns a Func<TArg1, TArg2>. Yes, you want to reduce the number of parameters - but by supplying the values, not by dealing with functions to convert from one argument type to another.
Jon Skeet
But you can use a func like () => "myValue"
Paco
@Paco: Yes, you can if you only want to use it in a single place. If you want to be able to use the resulting function several times, currying it explicitly can be helpful. It's nothing magical - you could use the body of the Curry method anywhere that you called the method - but it's just handy.
Jon Skeet
The problem is see with the separate Curry function is that i push the work from me to the user of my code. Where to place the Curry function? There aren't global functions in C#.
Rauhotz
Yes, it's the Math.Sin problem again. Java's static imports are a nice solution to this. I do think it's nicer to have it in one place than duplicating this for each method that it might be applicable for though.
Jon Skeet
I'll try if extension methods likepublic static Func<T> Curry<T0, T>(this Func<T0, T> func, T0 arg0)work
Rauhotz
Unfortunately extension methods don't work on lambda expressions: http://msmvps.com/blogs/jon_skeet/archive/2008/01/08/extension-methods-on-lamdba-expressions-don-t-work-unfortunately.aspx
Jon Skeet
I agree with Paco. IMO this solution does partial application, not currying. See http://lambda-the-ultimate.org/node/2266
Mauricio Scheffer
However, the solution fits the question
Mauricio Scheffer
I suspect that both myself and the original questioner are confused as to what currying means. It sounds like a lot of the rest of the world is too. Interesting question: is it too late to rescue the term? Should we give up on it and start with the same definition, but for a new term? Sounds awful..
Jon Skeet
I see there's even a question here on SO to disambiguate: http://stackoverflow.com/questions/218025/what-is-the-difference-between-currying-and-partial-application
Mauricio Scheffer
Cool - that's a much clearer explanation than I've seen elsewhere :)
Jon Skeet
+1  A: 

Did you check this blog post? http://mikehadlow.blogspot.com/2008/03/currying-in-c-with-oliver-sturm.html

rodbv
+2  A: 

I find the notion of currying very interesting, but ultimately not very useful. I'm probably 1/3 way there to groking currying, but still need a little push!

Could somebody post an example of C# currying which actually solves a practical problem?

David Kirkland