When coding in F#, you really get used to the automatic currying the language provides. It feels just natural. However, F# lives within the .NET world, so sooner or later, you have to call some function from the BCL or another assembly you have coded in C#. Problem is, F# maps the method parameters as tuples, so they are uncurried. Let's take for example String.Compare(string,string). When coding in F#, its signature is (string * string) -> int so you have to call it just like you would in C#:
String.Compare("something", "something else")
If it were curried, its signature would be string -> string -> int, so you could call it like this:
String.Compare "something" "something else"
This little difference can get quite annoying. It feels like an "exceptional" call when you have to put the parens.
Of course, it's not arbitrary that F# doesn't automatically curry every function in the framework. For example, curried functions are actually implemented with FastFuncs, so String.Compare would have to be wrapped in a function that took a string and returned a FastFunc<string, int> closure which in turn calls the actual String.Compare. No such thing as a free lunch :-)
So I set out to either find or develop a way to curry any function.
In statically typed languages it's more complicated. The difference seems to be that arity isn't a concept as strong in dynamic languages as it is in statically typed ones. In C#, although not a mainly functional language, generalized currying can be implemented by creating different overloads of a curry function, one for each arity. Haskell has its own set of solutions, which I'll someday understand but not today :-)
I asked on hubFS, it seems that there isn't anything standard yet for F#. So I tried to use method overloading to overcome the arity problem. The result is this boring code, similar to Dustin's solution:
type FP = static member curry2 (f:_*_ -> _) = fun a b -> f (a,b) [<OverloadID("curry2")>] static member curry (f:_*_ -> _) = FP.curry2 f static member curry3 (f:_*_*_ -> _) = fun a b c -> f (a,b,c) [<OverloadID("curry3")>] static member curry (f:_*_*_ -> _) = FP.curry3 f static member curry4 (f:_*_*_*_ -> _) = fun a b c d -> f (a,b,c,d) [<OverloadID("curry4")>] static member curry (f:_*_*_*_ -> _) = FP.curry4 f static member curry5 (f:_*_*_*_*_ -> _) = fun a b c d e -> f (a,b,c,d,e) [<OverloadID("curry5")>] static member curry (f:_*_*_*_*_ -> _) = FP.curry5 f static member curry6 (func:_*_*_*_*_*_ -> _) = fun a b c d e f -> func (a,b,c,d,e,f) [<OverloadID("curry6")>] static member curry (func:_*_*_*_*_*_ -> _) = FP.curry6 func
But this has problems when trying to curry overloaded methods:
- FP.curry String.Compare doesn't work, since the compiler doesn't know which overload to pick. (there are ten overloads!)
- FP.curry2 String.Compare works fine, since we are explicitly telling the compiler the arity of the method, and there is only one overload with two parameters; however:
- FP.curry3 String.Compare fails, because there are two overloads of String.Compare with three parameters.
Conclusion: this is not a good way to implement generic currying in F#. It would be very nice to have this integrated into the language, but I wouldn't hold my breath. As a workaround, I'll consider implementing a post-build step using Mono.Cecil to create the necessary FastFunc wrappers.