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.
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.
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!
What's wrong with:
var list = string.Join(",",Enumerable.Range(1, 100).Where(i => i%2 == 0));
I don't really see how this is not functional programming. It's less chaining, true. But functional program is not about chaining, it's about writing more declarative statements, which this is doing in my book. Of course, if you really want it to be chained you can do this: What is the LINQ way to implode/join a string array?
I'm not sure why you need the additional Curry method from your example. Simply using another Lambda produces a more terse option.
var list = Enumerable.Range(1, 100)
.Where(i => i%2 == 0)
.ApplyTo((x) => { return string.Join(",", x); })
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With