Grand Func Railroad - Functional .. erm. functions


A while ago I read an an excellent post by Andrew Matthews (on his excellent Wandering Glitch blog) about employing functional programming techniques in C# that are enabled by the new features added in C#3.0. Now, I did wonder about posting about this as it contains the same subject matter as the information in Andrews blog (and Andrew describes the hows and whys a lot better than me), but I wanted to post for two seperate reasons.

  1. I use these two functions (below) ~all~ the time now. They are fantastic and (thanks to Andrew) have opened up my code up to this powerful programming technique and wanted to share them here incase they help anyone else.
  2. While I really liked Andrews examples it took me a while to grok them completely thanks to one problem that plagues me as a person bug-bear .. one letter variables as arguments.

I hate, hate, hate one letter variables when used as arguments, I know the problem here is a personal one .. mainly that I am not (or have ever been) a mathematician I didnt do A-Level maths, I was a graphics, pixel art, 3d artist kind of guy who found his way into programming by accident and while now I would never consider myself anything other than a programmer, math-type syntax makes my brain run in the opposite direction .. i.e the original On (which becomes my "Apply"):

Func<T, T> On<T>(this Func<T, T> f, Func<T, T> g)
{
   
return t => g(f(t));
}

 

In learning about these functional techniques (also including my learning with F# as well) I come across time and time again peoples examples that are clearly for the mathematically minded (ie not me hehe!) so I wanted to try and re-present these two functions in the syntax that finally got me to understand them.

I doing this I have to strongly emphasise that I am not "having a go" at anyone, especially not Andrew, as i wouldnt be here if people didnt post such great articles showing new ways of doing stuff, this simply exists to provide a level of clarification for the thickies :D Enough of my jibber-jabber ..

ApplyToSequence

This extension function takes a function as the argument and then applies that function to every element of the IEnumerable list. While being simple its is a very powerful tool, it already exists in one degree in the BCL, if you create a List<T> you can use the .ForEach() method but this function allows you to perform an action on ~anything~ IEnumberable (which makes it very handy ! Although i dont know why this isnt a standard method for IEnumerable already). An example follows these descriptions.

static IEnumerable<TResult> ApplyToSequence<T, TResult>(this IEnumerable<T> sourceSequence, Func<T, TResult> functionToApply)
{
   
foreach (var element in sourceSequence)
    {
        
yield return functionToApply(element);
    }
}

Apply

This extension method take a function as an argument and then applies that function to the original one. The great thing about this is it enable you to "chain" functions togther to make concise, powerful code.

static Func<T, T> Apply<T>(this Func<T, T> sourceFunction, Func<T, T> functionToApply)
{
   
return t => functionToApply(sourceFunction(t));
}

Examples

Here we go .. putting these two simple functions together means we can start doing quite neat things.

    // Two functions one which takes an int and adds 1 to it
    var addOne = ((Func<int, int>)(a => a + 1));

   
// .. and another that take an int and subtracts
   
var subOne = ((Func<int, int>)(a => a - 1));

   
// Two IEnumerables (one int and one string)
   
IEnumerable<int> test = new [] { 22, 44, 553, 345, 23, 32 };
   
IEnumerable<string> test2 = new [] { "<head>", "</head>" };

    // Print originals ..
   
foreach (var i in test)
    {
       
Console.WriteLine(i);
    }

    Console.WriteLine("-----------------------");

   
// Add 1 to each value .. using ApplyToSequence to apply the addOne
    // function to each element.
   
test = test.ApplyToSequence(addOne);

    foreach (var i in test)
    {

       
Console.WriteLine(i);
    }

   
Console.WriteLine("-----------------------");

    // By chaining the functions together we can add 3 then
    // subtract 1 from each element .. in one line too ..
   
test = test.ApplyToSequence(addOne.Apply(addOne).Apply(addOne).Apply(subOne));

   
foreach (var i in test)
    {
       
Console.WriteLine(i);
    }

    Console.WriteLine("-----------------------");

    foreach (var i in test2)
    {
       
Console.WriteLine(i);
    }

    Console.WriteLine("-----------------------");

    // Using ApplyToSequence we can also apply another function to
    //
 a string to do useful things like escaping characters
   
test2 = test2.ApplyToSequence(i => EscapeString(i));
   
   
foreach (var i in test2)

    {
       
Console.WriteLine(i);
   
}

   
Console.WriteLine("-----------------------");

The power of these should (hopefully) speak for themselves and I found myself using these a hell of a lot in recent code. The how and why these functions work or are able to work is described brilliantly in Andrews original article, I hope my lazy renaming simply helps shed some light on these for the less mathematically minded out there :)

 


Posted by: [mRg]
Posted on: 6/4/2008 at 10:55 AM
Tags: ,
Categories: Guides
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (2) | Post RSSRSS comment feed

Related posts


Comments

Andrew Matthews

Monday, June 09, 2008 2:29 PM

Sorry for writing it using my off-putting single-char variable names. I would never stand for that during a code review - it's just that as i was thinking of the composition all the old maths examples came flooding back and I threw caution to the wind. Tong

NICE Post BTW.

Mute

Monday, June 23, 2008 6:40 PM

Sweet article bro, I gotta learn me some c# Smile

Do you have to be careful not to over-use this in your projects? I can imagine if you don't document it very well it could become hard to follow.

Add comment



(Will show your Gravatar icon)  

  Country flag

biuquotepaste

  • Comment
  • Preview
Loading