currying in c#

Today i want to write about a functional programming topic. This topic is curried functions. To curry a function is named after the mathematician Haskell Curry and means to build a function with n – 1 parameters out of a function with n parameters. If you have the function:

Func<int, int, int> mul = (x, y) => x * y;

the curried function out of this Function would be:

Func<int, Func<int, int>> curriedMul = mul.Curry();

That means that the curried function takes only one parameter and returns a function with one parameter. If we now call the curried function:

Func<int, int> executedCurriedMul = curriedMul(2);

Now the function executedCurriedMul has saved the first paramter (2) in the function. If we now call the resulting function

 int mulResult = executedCurriedMul(3);
 Console.WriteLine(mulResult);
 6

it returns 6. That means that we split up the pass of the parameters.
Alternative we could invoke the curried function this way:

int mulResult = curriedMul(2)(3);

In haskell every function is a curried function:

mult :: Integer -> Integer -> Integer
mult a b = a * b

*Main> let curriedMult = mult 2
*Main> curriedMult 3
6

In f# also every function is a curried function:

let mult a b = a * b
let curriedMult = mult 2.0
let multResult = curriedMult 3.0

printfn "result = %f" multResult
6.0

but in c# we need a extension method to curry a given function.

//Currying a function with two parameters using anonyme methodes.
//The method generates two nested anonymus methodes.
//with the call of the method a delegate to a anonymus method 
//with one parameter of type T1 and a return type of type
//Func<T1, Func<T2, TResult>> is created.
//if the curried function is called we overtake the p1 parameter (first parameter)
//and get back a Func<T2, TResult> func delegate.
//if we now call the returned Func<T2, TResult> with parameter p2 (second parameter)
//we call the func function with p1 and p2. That works because p1 becomes a closure and
//so we can use it in the second call.
public static Func<T1, Func<T2, TResult>>
    CurryAnonym<T1, T2, TResult>(this Func<T1, T2, TResult> func)
{
    return (Func<T1, Func<T2, TResult>>)delegate(T1 p1)
    {
        return (Func<T2, TResult>)delegate(T2 p2)
        {
            TResult tresult = func(p1, p2);
            return tresult;
        };
    };
}

//Currying a function with two parameters using lambda expressions
//the return type of the Func<T1, Func<T2, TResult>> delegate is explicite to
//make the return types clear. It works the same way a the CurryAnonym function
//but it uses lambda expressions instead of anonym methodes.
public static Func<T1, Func<T2, TResult>>
    Curry<T1, T2, TResult>(this Func<T1, T2, TResult> func)
{
    return new Func<T1, Func<T2, TResult>>(
            p1 => new Func<T2, TResult>(
                p2 => func(p1, p2)
                )
        );
}

//Currying a function with three parameters using lambda expressions
public static Func<T1, Func<T2, Func<T3, TResult>>>
    Curry<T1, T2, T3, TResult>(this Func<T1, T2, T3, TResult> func)
{
    return p1 => p2 => p3 => func(p1, p2, p3);
}

//Currying a function with four parameters using lambda expressions
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 p1 => p2 => p3 => p4 => func(p1, p2, p3, p4);
}

//Uncurry a function with two parameters. Here we overtake the curried function
//and build a new Func<T1, T2, TResult> lambda function 
//that executes the curried function
public static Func<T1, T2, TResult>
    Uncurry<T1, T2, TResult>(this Func<T1, Func<T2, TResult>> func)
{
    return new Func<T1, T2, TResult>(
            (p1, p2) => func(p1)(p2)
        );
}

With this extension methodes it is easy to build a curried function. With the Uncarry extension method it is also possible to revoke the currying of a function.

Advertisements


If you have a note or a question please write a comment.

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s