jQuery is a Monad

January 18, 2009 at 4:53 am

It’s said that every Haskell programmer writes their own monad tutorial, and with good reason: once you finally understand the definition and capabilities of a monad, you’ll be eager to try and break the mystique surrounding the concept of monads as a whole. To the outsider, monads are an impenetrable barrier to truly understanding Haskell; they’re cursed with a very unfortunate name, have bizarre syntax, and seem to do a thousand things at once. However, monads aren’t hard to understand when you see them in action.

As such, I present to you what may be the most widely-used monadic library in any language: the jQuery library, designed to bring Javascript back to its roots in functional programming and make AJAX and animations easy. The jQuery object, accessible through the jQuery variable or the $ shortcut, allows you to query or make DOM elements using CSS selectors or XPath queries, as shown below:

$("div"); // all div elements

$("span.moveable") // all spans with the moveable class

$("em,strong"); // all emphasized and strong tags

$("div\[img][3]"); // the third div that contains an image

It may be somewhat alarming, but jQuery all but eliminates the need for instance variables thanks to its method chaining. If I wanted to take all the span elements, fade them in, then set their text to “Alert!”, all without jQuery, I would need instance variables to save the found elements, to keep track of elapsed time, and perform each operation sequentially. In jQuery, it’s much easier:

$("span").fadeIn("slow").text("Alert!");

The returned result of fadeIn is not null, as one might otherwise assume, but the very same jQuery container $("span") upon which it was called. That way, I was able to call the .text("Alert!") method, which likewise returns the same container. Method chaining like this gives an immense dose of power, concision and readability to a previously flabby language. In addition to DOM manipulation, jQuery provides powerful AJAX shortcuts, attractive yet unobtrusive animations, and extensive CSS manipulation.

The Monadic Laws

Now that you have a basic idea of the concepts upon which jQuery is founded, let’s take a look at the three monadic laws. (The concept of monads and the monadic laws were first codified in the branch of mathematics known as category theory – beware, the previous link is dense as hell.)

The first monadic law is that a monad is a wrapper around another type. In Haskell, one has the IO String type, which is returned from functions that read from files, console input, or system calls – IO is a monad that wraps the String data type. jQuery obviously satisfies this condition, as it wraps DOM nodes retrieved through given queries.

The second monadic law is just as simple: all monads must have a function to wrap themselves around other data types. jQuery clearly has ways to apply itself to DOM nodes – you use the querying facilities to traverse the DOM, and if you’re feeling especially saucy, you can use pass the results of document.getElementsByTagName and its siblings to the jQuery object. Haskell refers to this as a type constructor – a function that takes some data and wraps that data inside a new type. (jQuery’s type constructor is its parentheses.)

The third monadic law, and the only one that’s even remotely complicated, is that all monads must be able to feed the value or values that they wrap into another function, as long as that function eventually returns a monad. fadeIn() , text() , and all the other chainable functions are examples of this – they take the elements given inside the jQuery object, perform their function on them, then rewraps them back into the jQuery object and returns them. And don’t think that you’re just limited to the built-in functions on the jQuery object – using the map() function, you can pass an anonymous function that will be called on each DOM element inside the jQuery object. map() will still return the jQuery object upon which it was called.

So, let’s review. Monads are abstract data types that satisfy three conditions:

1) They wrap themselves around other data types

2) They have an operation, confusingly called return , that actually performs the aforementioned wrapping

3) They have an operation called bind that allows to feed the value wrapped inside the monad into another function, as long as the function returns a monad.

Bam. That’s it. Simple – almost so simple as to be useless. But monads are like objects in that though they are conceptually very simple, they are immensely powerful. In Haskell, monads are used as an abstract datatype to represent actions – since they an be chained together, they a perfect fit for traditional imperative programming or code that depends on the outside world. Any keyboard input or file input in Haskell is wrapped inside an IO monad, serving to indicate that this part of the program is dependent on the outside world. By indicating that only certain sections of your programs depend on external, unpredictable input you not only make your debugging easier but also ensure that the rest of your functions depend only on their inputs. If you’re interested in learning about the other ways that Haskell uses monads or learning a stricter definition of monads, check out Jeff Newburn’s All About Monads.

“This is all well and good”, you say, “but how does jQuery’s monadic implementation manifest itself in common jQuery idioms?” Well, I’m glad that you asked.

Cautious Computations

Each language has its own way of dealing with passing a null object to a function that expects a non-null object or sending a message to a null object. Objective-C returns nil, Java throws NullPointerExceptions, and C – well, C segfaults, but what else is new? The jQuery equivalent of this would be trying to manipulate the contents of an empty jQuery object, like so:

$([]).fadeOut().text("THE WORLD HAS BROKEN!");

By calling the jQuery’s type constructor with an empty array as a parameter, we get an empty jQuery object; even though I’m calling fadeOut() and text() on nothing at all, jQuery will fail gracefully rather than spew errors all over the console. Much like Objective-C’s behavior when messaging nil or Ruby’s andand , this allows you to chain a long series of computations that may fail at some point together safely. From a higher-level perspective, this is very similar to Haskell’s Maybe monad, used to represent computations that might fail, such as a hashtable lookup.

State Transformations

When I heard that variables in Haskell could never change, I was horrified. Sure, I knew there are ways to work around this – recursion is the primary way – but I knew that there had to be some corner case where I would need to destructively update variables. It turns out I didn’t need to worry, because one of the most useful monads is the State monad. Not only does the State monad provide a vehicle in which to bind variables like you would in a regular language, but it also provides a useful semantic distinction – the very presence of the State monad in a function’s type implies that it depends on some state. (Now that I think about it, Haskell’s type system alone is more expressive than most languages.)

jQuery can be seen as a state monad too – it encapsulates a set of DOM nodes and allows you to chain stateful computations upon them. There are simple methods to change what is matched – add() adds new elements to the current object, contents() matches all children of the wrapped DOM nodes, and so on and so forth. The andSelf() and end() methods are much more interesting and much more reminiscent of Haskell’s state monad. Let’s take a look at how they work:

$("div.sidebar").find("a").andSelf().addClass('disabled')

In the above snippet, the $(“div.sidebar”) finds a div element with the sidebar class, and the find("a") class matches all links inside the sidebar. Were we to manipulate the jQuery object right now, only the links would be modified – instead, we add andSelf() , which readds the matched div element. We then add the ‘disabled’ class. end() performs the converse of andSelf() – it removes the elements matched by the previous destructive operation:

$("div.sidebar").find("a").addClass('disabled').end().fadeOut()

Conclusions

Monads aren’t esoteric, abstruse computer science – they’re useful. You probably have used monads but just haven’t realized it. jQuery is awesome.

And with that, I will go and observe DC descend into delicious chaos.

Share this: Twitter

Facebook

Like this: Like Loading... Related

Entry filed under: code. Tags: functional, javascript, jquery, monad.