Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# lambda - curry usecases

Tags:

c#

.net

lambda

I read This article and i found it interesting.

To sum it up for those who don't want to read the entire post. The author implements a higher order function named Curry like this (refactored by me without his internal class):

 public static Func<T1, Func<T2, TResult>> 
             Curry<T1, T2, TResult>(this Func<T1, T2, TResult> fn)
 {
     Func<Func<T1, T2, TResult>, Func<T1, Func<T2, TResult>>> curry = 
     f => x => y => f(x, y);
     return curry(fn);
 }

That gives us the ability to take an expression like F(x, y) eg.

Func<int, int, int> add = (x, y) => x + y;

and call it in the F.Curry()(x)(y) manner;

This part i understood and i find it cool in a geeky way. What i fail to wrap my head around is the practical usecases for this approach. When and where this technique is necessary and what can be gained from it?

Thanks in advance.

Edited: After the initial 3 responses i understand that the gain would be that in some cases when we create a new function from the curried some parameters are not re evalued. I made this little test in C# (keep in mind that i'm only interested in the C# implementation and not the curry theory in general):

public static void Main(string[] args)
{
    Func<Int, Int, string> concat = (a, b) => a.ToString() + b.ToString();
    Func<Int, Func<Int, string>> concatCurry = concat.Curry();
    Func<Int, string> curryConcatWith100 = (a) => concatCurry(100)(a);

    Console.WriteLine(curryConcatWith100(509));
    Console.WriteLine(curryConcatWith100(609));
}

    public struct Int
    {
        public int Value {get; set;}

        public override string ToString()
        {
             return Value.ToString();
        }

        public static implicit operator Int(int value)
        {
            return new Int { Value = value };
        }
    }

On the 2 consecutive calls to curryConcatWith100 the ToString() evaluation for the value 100 is called twice (once for each call) so i dont see any gain in evaluation here. Am i missing something ?

like image 874
Adrian Zanescu Avatar asked Feb 06 '09 12:02

Adrian Zanescu


1 Answers

Currying is used to transform a function with x parameters to a function with y parameters, so it can be passed to another function that needs a function with y parameters.

For example, Enumerable.Select(this IEnumerable<T> source, Func<TSource, bool> selector) takes a function with 1 parameter. Math.Round(double, int) is a function that has 2 parameters.

You could use currying to "store" the Round function as data, and then pass that curried function to the Select like so

Func<double, int, double> roundFunc = (n, p) => Math.Round(n, p);
Func<double, double> roundToTwoPlaces = roundFunc.Curry()(2);
var roundedResults = numberList.Select(roundToTwoPlaces);

The problem here is that there's also anonymous delegates, which make currying redundant. In fact anonymous delegates are a form of currying.

Func<double, double> roundToTwoPlaces = n => Math.Round(n, 2);
var roundedResults = numberList.Select(roundToTwoPlaces);

Or even just

var roundedResults = numberList.Select(n => Math.Round(n, 2));

Currying was a way of solving a particular problem given the syntax of certain functional languages. With anonymous delegates and the lambda operator the syntax in .NET is alot simpler.

like image 82
Cameron MacFarland Avatar answered Sep 29 '22 09:09

Cameron MacFarland