Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Challenge: Neater way of currying or partially applying C#4's string.Join

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!

like image 757
Damian Powell Avatar asked Apr 17 '10 14:04

Damian Powell


2 Answers

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?

like image 191
tster Avatar answered Oct 11 '22 21:10

tster


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); })
like image 38
Reid Evans Avatar answered Oct 11 '22 19:10

Reid Evans