The Thrush combinator in C#

Posted by Jonas Elfström Tue, 06 Oct 2009 18:35:00 GMT

Last year I read Reg "Raganwald'" Braithwaite's excellent post The Thrush and he explains it as

The thrush is written Txy = yx. It reverses evaluation.

Back then I didn't even consider trying to implement it in C#. That was before I digged deeper into lambda expressions and extension methods in C# 3.0 and way before last night when I read Debasish Ghosh's post on how to implement the Thrush in Scala. After reading that my first thought was if it was possible to do the same in C#. Here's my attempt.

At first I struggled with the static typing and headed for an easy way out using Object in the extension method of Object:

public static object Into(this Object obj, 
                        Func<object, object> f)
{  return f.Invoke(obj); }

My goal was to translate the Ruby example

(1..100).select(&:odd?).inject(&:+).into { |x| x * x }

in Raganwald's post to C#.

Which reads "Take the numbers from 1 to 100, keep the odd ones, take the sum of those, and then answer the square of that number."

But with the Object based extension method I had to do some ugly casts.

var r = Enumerable.Range(1, 100).Where(x => Odd(x)).Sum().Into(x => (int)x * (int)x);

With som added typing I could do:

var result = Enumerable.Range(1, 100).Where(x => Odd(x)).Sum().Into(x => x * x);

That merely moved the cast to the extension method and also made it work for integers only.

public static int Into(this Object obj, Func<int, int> f)
{ return f.Invoke((int)obj); }

Then I remembered generics and method type inference which finally led to a decent Thrush combinator in C#.

public static T Into<T>(this T obj, Func<T, T> f)
{ return f(obj); }

The casts are gone and it's also, as far as I can see, as flexible as the one in Ruby.

Contrived example follows:

var test = "ball";
var ball = test.Into(s => "Are we having a " + s + " yet?");

The odd part

The Odd(x) method call in the calculation above is a plain static method.

private static bool Odd(int n)
{ return (n % 2 != 0); }

If you want an even more terse syntax you could try an ext. method on IEnumerable like this:

public static IEnumerable<int> Odd(this IEnumerable<int> en)
{ return en.Where(n => n % 2 != 0); }


var result = Enumerable.Range(1, 100).Odd().Sum().Into(x => x * x);

In C# I don't think it's possible to pull off the Symbol#to_proc stuff that Ruby does. That's the &: in the select(&:odd?) and the inject(&:+) in the Ruby example. Raganwald has a great post on that.


Check out Jon Skeet's nice answer on StackOverflow to my question on how to make this even more Ruby-like. I have to try out that Operator class later though.

Edit 2009-10-07

One thing I found a bit surprising is that by implementing the Into ext. method in this way it not only works for all objects based on System.Object but it also works for value types.

int n=4711;
int oddOrZero = n.Into(x => x % 2 !=0 ? x : 0); // 4711
n = 4712;
oddOrZero = n.Into(x => x % 2 != 0 ? x : 0); // 0

Edit 2009-10-12

My confusion did stem from my lack of understanding of extension methods. Ex. methods are in fact not extending System.Object or any other type, they are "nothing more than a pleasant syntax for calling a static method" in case no instance method with the same name can be found.

Posted in Ruby, C# | 1 comment


    1. Avatar
      Reginald Braithwaite Tue, 06 Oct 2009 22:52:31 GMT

      Great post!

Comments are closed