JHarjung

So now that we've got lambdas, is there any chance we can get some help from the compiler with currying too :) It can be done at runtime (see code sample), but it doesn't seem terribly efficient, and it still requires writing out embedded Func<Func<...>, Func<...>> declarations by hand (blech!)

I'd love to be able to write this instead:

var f = curry(new Func<int, int, int>(SomeMethod))(3);

int result = f(10);

Or:

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

var g = curry(f);


Re: Visual C# 2008 (Pre-release) Curry, anyone?

Marcelo Guerra - MSFT

Hi,

I hope you are still subscribed to this so you can comment. This would be my solution to the "I'd love part".

static Func<A1, Func<A2, R>> Curry<A1, A2, R>(Func<A1, A2, R> f)

{

return a1 => a2 => f(a1, a2);

}

static int Add(int a, int b)

{

return a + b;

}

static void Main(string[] args)

{

var f = Curry(new Func<int, int, int>(Add))(3);

int result = f(10);

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

var g = Curry(f1);

}

Using the same idea I refactored your code into:

class Program

{

static Func<A1, Func<A2, Func<A3, R>>> Curry<A1, A2, A3, R>(Func<A1, A2, A3, R> f)

{

return a1 => a2 => a3 => f(a1, a2, a3);

}

static void Main(string[] args)

{

List<int> list1 = new List<int>();

for (int i = 1; i <= 10; i++)

{

list1.Add(i);

}

List<int> list2 = list1.Select(n => n + 10).ToList();

var fBase = Curry(new Func<Func<int, int, int>, int, IEnumerable<int>, IEnumerable<int>>(Aggregate<int, int>));

var f1 = fBase((s, a) => s + a)(0);

var f2 = fBase((s, a) => s - a)(0);

Console.WriteLine("F1(List1)");

PrintList<int>(list1, f1(list1));

Console.WriteLine("F1(List2)");

PrintList<int>(list2, f1(list2));

Console.WriteLine("F2(List1)");

PrintList<int>(list1, f2(list1));

Console.WriteLine("F2(List2)");

PrintList<int>(list2, f2(list2));

Console.ReadLine();

}

private static void PrintList<T>(List<T> Input, IEnumerable<T> Result)

{

using (IEnumerator<T> e = Result.GetEnumerator())

{

int index = 0;

while (e.MoveNext())

{

Console.WriteLine("x = " + Input[index++].ToString() + ": " + e.Current.ToString());

}

}

}

private static IEnumerable<TReturn> Aggregate<TInput, TReturn>(Func<TInput, TReturn, TReturn> Reducer, TReturn Seed, IEnumerable<TInput> List)

{

foreach (TInput x in List)

{

Seed = Reducer(x, Seed);

yield return Seed;

}

}

}

Hope this helps!

Marcelo.





Re: Visual C# 2008 (Pre-release) Curry, anyone?

JHarjung

Hmm...that does make it a bit cleaner. Actually, I didn't know you could omit the generic parameter types when calling a generic method - very nice Smile Curry(blah) looks a lot nicer than Curry<blah1, blah2, blah3>(blah).

And your solution doesn't require reflection, which is a plus. It does require a Curry function for every possible number of parameters though... I guess you could define a class somewhere that contained Curry methods for all possibilities from 2 to 100 or something.

Actually, what would be really cool is some syntactic sugar w/ the compiler so you could just write Curry(Aggregate) or Curry(Add) without having to write the new Func<...> part at all. var f = Curry(Aggregate);

Edit: On second thought, I guess method overloading would get in the way of Curry(Add)...the compiler wouldn't know which version of Add you wanted...





Re: Visual C# 2008 (Pre-release) Curry, anyone?

Marcelo Guerra - MSFT

We already have the problem of multiple functions, one for each signature, with Func, and the solution is what you said only that Func only exist for 1 to 4 parameters. Same thing with Action. So we can have one Curry for each Func Smile

Marcelo.





Re: Visual C# 2008 (Pre-release) Curry, anyone?

Luke Hoban

Just to add one more sample (very similar to what Marcelo posted above)....I have a small library of functional helpers that I use in personal coding projects - which includes:

Code Snippet
public static Func<T,Func<U,R>> Curry<T,U,R>(this Func<T,U,R> f) {
return t=>u=>f(t,u);
}

public static Func<T,U,R> UnCurry<T,U,R>(this Func<T,Func<U,R>> f) {
return (t,u)=>f(t)(u);
}

public static Func<T,Func<U,Func<V,R>>> Curry<T,U,V,R>(this Func<T,U,V,R> f) {
return t=>u=>v=>f(t,u,v);
}

public static Func<T,U,V,R> UnCurry<T,U,V,R>(this Func<T,Func<U,Func<V,R>>> f) {
return (t,u,v)=>f(t)(u)(v);
}

Of course, as mentioned, I'd need to add a few more overloads to make this more complete.

Thanks,

Luke Hoban

Visual C# Compiler Program Manager