How I understood monads, part 2/2: have we met before?
The first post in this series can be found here:
http://weblogs.asp.net/bleroy/archive/2010/06/16/how-i-understood-monads-part-1-2-sleepless-and-self-loathing-in-seattle.aspx
Last time, I tried to explain how beer and Lou helped me finally understand monads. I gave a couple of trivial examples. Hopefully now that you have this new functional hammer, everything will start looking like a nail.
So let’s have a look at a few screws this time.
Like last time, I’ll be pretty liberal with the definition of a monad as long as the spirit of monads seems to be preserved. Feel free to nitpick in the comments ;)
Oh yeah, jQuery is a monad
In jQuery, you first create a wrapped set of HTML elements and then execute operations on it, the result of which is a new wrapped set:
$(".foo") .filter(":odd") .map(function () { return this.id; });
Seems familiar? That because it is: the wrapped set is a monad. Pretty much.
The unit function of the monad, which is responsible for boxing an object into the monadic type is the $ function: $(elt) is building the wrapped set for the elt element.
The binding operation is more implicit than it’s been in previous C# examples and consists in just executing one of the built-in set operations or one of the plug-ins: the operation is specified by simply calling it. So for the monad to really take arbitrary operations there is a registration phase here (the registration of the plug-in) but what the operations themselves are doing is in the spirit of monads: they act on the underlying DOM or JavaScript types and return a new wrapped set.
Unboxing the wrapped elements is done by calling the get function.
Oh yeah, FluentPath is a couple of monads
Ah, here’s one I wrote before I even understood what a monad is (assuming that I do now). FluentPath is wrapping System.IO’s string paths and arrays of string paths into Path and PathCollection boxes. Once this is done, you can execute one of the built-in operations, the result of which is also a wrapped path or path collection. You can also execute custom operations:
var dirs = Path.Get("video") .GetFiles("*.avi", true) .Copy(p => p.Parent.Combine("backup").Combine(p.FileName)) .ChangeExtension(p => p.Extension + ".bak") .Map(p => p.Up(2));
This is pretty close to jQuery (for a reason, FluentPath was inspired by jQuery).
Path.Get is wrapping the path, the operations are method calls, with or without Lambda parameters.
An example of an arbitrary or custom operation on the set can be seen in the example above: the Map call is taking each element of the path collection and going two levels up on it. The result is a new wrapped set of paths.
Unboxing is done by calling ToString on a path.
Oh yeah, Linq providers are monads
Just look at this:
var l = new[] {"foo", "bar", "baz"} .Select(s => "... " + s) .Select(s => s + " bleroy was here.");
Looks familiar? Again, it should be. We could just as well write this same example this way:
var l = from s in from s in new[] {"foo", "bar", "baz"} select "... " + s select s + " bleroy was here.";
See? The IEnumerable<T> interface is the box and the selects are binding the operations.
What’s interesting here is that we have a way to specify operations on an enumeration of things that is independent from the kind of thing we’re working on: an array like above, or a SQL Server table, an XML document or whatever has a Linq provider.
It’s also independent of how the operations get executed: a Linq provider abstracts away how the expression of the operation gets translated into actual operations that the underlying type can understand.
This second abstraction is where the real magic in Linq resides: when you write a where clause in Linq, the actual implementation of that clause may be SQL or a C# operation or who knows what, but how you write the expression itself doesn’t change.
And while we’re talking about expressions…
Oh yeah, Expression<T> is a monad
An expression in .NET is a representation of a function:
Expression<Func<string, string>> expr = s => s + " appended some stuff.";
In this example, we are taking a Lambda and wrapping it into an expression object. The beauty of it is that this object can then be manipulated at runtime to build new expressions, which can then be unwrapped into functions and executed.
By now you should have seen where I’m going with this: boxing a Lambda is done by wrapping it into an Expression and unboxing is done by calling Compile() on the expression.
The Bind operation is less obvious and would not fit in this post but it can be done by implementing an expression tree visitor.
Oh yeah, Parallel.ForEach is a monad
The new parallel extensions in .NET 4 are quite interesting as they offer parallel computation under a familiar model.
For example, you can do this:
Parallel.ForEach( Directory.GetFiles("*.jpg"), path => { var bitmap = new Bitmap(path); bitmap.RotateFlip(RotateFlipType.RotateNoneFlipXY); bitmap.Save(path + ".flipped"); });
This code will execute a rotation operation on each JPEG image in the current directory, in parallel as much as possible, which is ideal for long-running and independent operations such as image manipulation.
What really happens is that the enumeration of files returned by Directory.GetFiles is getting wrapped into a ParallelEnumerable, and then the operation is getting executed on each of the elements of the enumeration in parallel.
The boxing operation is thus represented here by the AsParallel method (which is implicitly called by Parallel.ForEach). The binding operation of the monad is Parallel.ForEach.
What we are seeing here is a monad whose only goal is to provide a different execution model for an existing operation. The value of the monad pattern is quite clear in this example: a familiar programming model is being quite naturally extended.
Oh yeah, C#4’s dynamic is a monad
Thanks to the new dynamic keyword in C#4, it is now possible to ask the C# compiler to relax compile-time type checking and instead resolve the members of some objects at runtime.
Here’s a somewhat trivial example:
dynamic foo = new { bar = "baz" }; Console.WriteLine(foo.bar);
This example is rather pointless but what’s important is that what can be wrapped into a dynamic object comes in many shapes: .NET objects can be accessed this way (through reflection), but you can also wrap COM objects or pretty much anything provided that somebody wrote the code to resolve the underlying type system at runtime.
Boxing is done by assigning the object from the underlying type system to a dynamic variable like above. You can then perform any C# operations on the wrapped object and access the members of the underlying type system exactly as if it were a native .NET object.
The monad binding is implicit here. What really happens is that the operations are being delegated at runtime to the underlying type system by the dynamic object provider.
Monads everywhere
With functional programming becoming more mainstream and insidiously getting into more “classical” languages such as C# or JavaScript, it’s probably not such a big surprise that its patterns would find their way into our everyday APIs. Once you know the monad pattern, all sorts of things that you weren’t noticing before suddenly seem to jump into focus, like one of those optical illusions that at first you don’t see, and that once you see cannot be unseen.
Did you spot monads in familiar places? Let me know in comments.
Next time, I’ll look at expressing monads with CallStream, and after that I’ll make a post to answer some of the comments I got on this post and the previous one, such as “why should I care?”