Background
I recently read that .NET 4's System.String class has a new overload of the Join method. This new overload takes a separator, and an IEnumerable<T>
which allows arbitrary collections to be joined into a single string without the need to convert to an intermediate string array.
Cool! That means I can now do this:
var evenNums = Enumerable.Range(1, 100)
.Where(i => i%2 == 0);
var list = string.Join(",",evenNums);
...instead of this:
var evenNums = Enumerable.Range(1, 100)
.Where(i => i%2 == 0)
.Select(i => i.ToString())
.ToArray();
var list = string.Join(",", evenNums);
...thus saving on a conversion of every item to a string, and then the allocation of an array.
The Problem
However, being a fan of the functional style of programming in general, and method chaining in C# in particular, I would prefer to be able to write something like this:
var list = Enumerable.Range(1, 100)
.Where(i => i%2 == 0)
.string.Join(",");
This is not legal C# though. Yes, I could do it with Enumerable.Aggregate
, and yes, I could do it with my own Join extension method), but those approaches are hard to read/inefficient and feel like a cop-out (respectively) so I would like to try and do it a different way. The closest I've managed to get so far, is this:
var list = Enumerable.Range(1, 100)
.Where(i => i%2 == 0)
.ApplyTo(
Functional.Curry<string, IEnumerable<object>, string>
(string.Join)(",")
);
...using the following extension methods:
public static class Functional
{
public static TRslt
ApplyTo<TArg, TRslt>(this TArg arg, Func<TArg, TRslt> func)
{
return func(arg);
}
public static Func<T1, Func<T2, TResult>>
Curry<T1, T2, TResult>(this Func<T1, T2, TResult> func)
{
Func<Func<T1, T2, TResult>, Func<T1, Func<T2, TResult>>> curried
= f => x => y => f(x, y);
return curried(func);
}
}
This is quite verbose, requires explicit definition of the parameters and return type of the string.Join overload I want to use, and relies upon C#4's variance features because we are defining one of the arguments as IEnumerable rather than IEnumerable.
The Challenge
Can you find a neater way of achieving this using the method-chaining style of programming?
This challenge is about trying to find a terse way, in C#, to curry a function that has multiple overloads - and it's just for fun!