Curry and Uncurry
Curry turns a function of several parameters into a chain of functions taking one parameter each.
Uncurry is the inverse.
Func<T1, Func<T2, TResult>> Curry<T1, T2, TResult>(Func<T1, T2, TResult> function)
Func<T1, Func<T2, Func<T3, TResult>>> Curry<T1, T2, T3, TResult>(Func<T1, T2, T3, TResult> function)
// … up to eight parameters, and the same for Action<…>, where the innermost function is an Action
Func<T1, T2, TResult> Uncurry<T1, T2, TResult>(Func<T1, Func<T2, TResult>> function)
// … likewise
A curried function can be applied to its arguments one at a time, and applying it to the first argument gives you a new function that remembers it. That is partial application, and it is the practical reason to curry in C#: you fix the arguments you know and pass the rest on as a smaller function.
Func<int, int, int> add = (a, b) => a + b;
var curriedAdd = Curry(add); // Func<int, Func<int, int>>
var addFive = curriedAdd(5); // Func<int, int>
addFive(3); // 8
Enumerable.Range(1, 3).Select(curriedAdd(10)); // [11, 12, 13]
The curried form is what you need when an API wants a Func<T, TResult> and you have a two-argument method
plus one of the arguments at hand. Without Curry that is a lambda, x => Add(10, x), which is fine once
and noisy when repeated.
Uncurry goes the other way, which is rarely needed in C# but completes the pair: Uncurry(Curry(f)) is f.
Fn
Method groups do not have a type of their own, so the compiler cannot infer the type parameters of Curry
from one:
var pow = Curry(Math.Pow);
// error CS0411: The type arguments for method 'Functional.Curry<...>' cannot be inferred from the usage.
Fn is Identity restricted to the job of giving a method group its natural delegate type. Wrapping the method
group makes the inference work:
var pow = Curry(Fn(Math.Pow));
// or, using the extension method form
var pow = Fn(Math.Pow).Curry();
var square = pow(2.0); // wait, that is 2^x
That last line shows why Flip exists.