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:

1
2
3
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.

1
2
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#.

1
2
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:

1
2
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.

1
2
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:

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


Gives:

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.

Edit

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.

1
2
3
4
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

Comments

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

      Great post!

Comments are closed