Google

Previously we saw how jQuery's $() can behave like Haskell's Functor typeclass, when it wraps raw DOM objects and how provides its own version of fmap ($.map) for lifting functions into that wrapper to work with those DOM objects. In this post I'll explain Haskell's Applicative typeclass, how it's slightly different from the Functor, and demonstrate how defining functions on $.fn behaves in a similar fashion to the Applicative function pure.

The article assumes you've read the previous post and that you have some basic understanding of what it means to define a function on jQuery's $.fn object (docs for reference).

Applicative Functors

To start, the Applicative typeclass in Haskell requires that instances also be Functors. Practically speaking this means that any Applicative type actually builds on top of it's Functor by requiring an extra function and an operator, pure and <*>. This is important because it tells us that we're still working with contexts, the stuff in them, and getting operations inside to work on the stuff in them.

class Functor f => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b

Continuing with our practice of renaming types for clarity lets alter the definition a bit

pure :: a -> applicative(a)
(<*>) :: applicative(a -> b) -> applicative(a) -> applicative(b)

and being that any Applicative is also a Functor

pure :: a -> functor(a)
(<*>) :: functor(a -> b) -> functor(a) -> functor(b)

pure is relatively simple. From the type a -> applicative(a) you can see that its a function that takes some type a, wraps/lifts it into the Applicative, and hands that Applicative instance back. In the previous article on the Functor we didn't discuss how the data a or b got wrapped inside a Functor in Haskell. We took for granted the fact that the value would be wrapped because it was easy to illustrate in Javascript. This means that instances of a Functor might need to expose some way to do the wrapping or users have to create a function for that purpose outside the requirements of the Functor type class. In the case of Applicatives pure is a function that does the wrapping1.

Next, the infix operator <*>. Its type signature looks a little bit like fmaps:

fmap :: (a -> b) -> f a -> f b
(<*>) :: f (a -> b) -> f a -> f b

The only difference is that the first argument f (a -> b) is a function wrapped inside the Applicative context, where fmap takes a raw function and does the wrapping for you. You can probably imagine how pure is used with <*>, it wraps functions and data in the Applicative and then <*> is used to apply those wrapped functions to the wrapped data.

Javascript's this

Before we get started in demonstrating the jQuery analogue to the Applicative Haskell type class, we need to talk about this.

Because we're drawing analogies with pure functional programming, where arguments are always defined explicitly, and our jQuery analog will reference it as a replacement for arguments in the type class type signatures, we're going to think of this as an implicit parameter. This isn't too much of a stretch given that for any function/method invoked via Function.prototype.call and Function.prototype.apply, it's actually explicit.

A simple example

var foo = function(first, second){
  console.log(first);
  console.log(second);
  console.log(this);
};

foo.call("wow", 1, 2);
// -> 1
// -> 2
// -> [object]

foo.apply("wow", [1, 2]);
// -> 1
// -> 2
// -> [object]

The only issue with thinking this way is that this is treated as an object and not simply passed through as a parameter would be, though this doesn't affect our discussion. The important part to get for the rest of the article is that, just because it isn't declared as an argument, doesn't mean that this can't behave like one during invocation.

jQuery

To define our jQuery analog for the Applicative we have to implement the two functions from the Haskell type class. First pure and then the operator <*>. Luckily, once we sort out pure, the extra operator mostly sorts itself out.

Since pure wraps things in the Applicative, functions or data, and we already have a way to wrap the data, HTMLElements, with the jQuery $() function, all we really need to do is figure out how to get functions into the Applicative so they can operate on wrapped HTMLElement data. Your initial reaction might be to use the same wrapping function for HTMLElements and functions but in jQuery $(function(){}) is a callback for DOM ready so we'll need to find something else. For reference the type signature of the function we're looking for in Haskell would be

foo :: (a -> b) -> f (a -> b)

or in terms of the Applicative

foo :: (a -> b) -> applicative(a -> b)

The first argument is a function from a to b and the return type is a function from a to b, presumably the same one, wrapped in the Applicative. Obviously pure does just that since the type of a in its type signature pure :: a -> applicative(a) can be a function (a -> b).

Lets look at how functions defined on $.fn behave to see if that might suggest anything:

// definition
$.fn.clearIds = function(){
  $.map(this, function(e){
    e.id = "";
    return e;
  });

  return this;
};

// invocation
$( "div" ).clearIds();

Looking at the clearIds invocation it certainly appears that its been defined/lifted/wrapped to work with the $() wrapper/Applicative, but you'll notice that this inside the function body is a set of $() wrapped HTMLElements that must be mapped over and not the HTMLElements themselves. Assuming this as an implicit first parameter the type of the clearIds definition when translated back to Haskell would be something like:

clearIds :: $(a) -> $(b)
or in terms of the Applicative
clearIds :: applicative(a) -> applicative(b)

This should make perfect sense for anyone thats written a jQuery plugin meant to chain with other plugins or jQuery builtins. It takes a $() wrapped set of elements and returns the same so the next plugin method can operate on them.

While it does sort of resemble the function wrapped into the Applicative, applicative(a -> b), that we're looking, it is different. If you spotted the map call inside the clearIds definition you'll have noticed that the function references the id attribute directly from each HTMLElement. That function

function(e){
  e.id = "";
  return e;
}

has the type signature that we want to emulate, namely (a -> b), or more concretely (HTMLElement -> HTMLElement). If we can abstract the map call and the return of the mutated this we'll end up with a function that takes a function (a -> b) and results in a function that can work with the Applicative. Lets do that now:

$.pure = function(fromAToB){
  return function(applicative){
    return $.map(applicative, fromAToB);
  };
};

That's more like it. $.pure takes a simple function fromAtoB, meant to work with the raw HTMLElements wrapped inside the Applicative $(). The type signature is a bit off (a -> b) -> (f a -> f b), but lets take a look at the corresponding implementation of <*>, here referred to as ap to see if we've captured the spirit of the applicative.

$.fn.ap = function(applicativeFn){
  return applicativeFn(this);
};

ap will take the result of a call to $.pure, and uses it to alter the implicit parameter this which is $() wrapped HTMLElements. Including the this parameter the type signature is

$.fn.ap :: (f a -> f b) -> f a -> f b
which is is pretty close to what we're looking for
(<*>) :: f (a -> b) -> f a -> f b
when you consider that the descrepancy in the first argument is dictated by how functions defined on $.fn have to operate. The end result will look something like this for our clearIds example above:
var clearIds = $.pure(function(e){
e.id = "";
return e;
});
$( "div" ).ap(clearIds);

Here we've got all the necessary peices to fulfill the type requirements for both pure and <*>. $.pure does the wrapping for functions that operate on the elements of our jQuery Applicative, $() does the wrapping of the elements themselves (eg $( "div" )), and the ap method does the application of the lifted function to the HTMLElements. Thus the ap method defined on the $.fn object is our <*> opperator from Haskell so long as the method defined on the jQuery object has been created using $.pure!

A New JQuery Plugin Helper

We've fulfilled the requirements of the Applicative type class and derived a useful helper as a consquence, but asking the user to manage the results of the $.pure is clumsy. A simplification might take the form

$.pure = function(fnName, fromAToB){
$.fn[fnName] = function(){
return $.map(this, fromAToB);
};
};
with a definition and invocation for our clearIds example
$.pure('clearIds', function(e){
e.id = "";
return e;
});
$( "div" ).clearIds();

Here, the pattern of mapping a function of (a -> b) into the jQuery context is done as before by $.pure, but the storage is done on the jQuery $.fn object not by the user. As a consequence, we can simply invoke a function of fnName directly on the jQuery object as a substitute for ap, <*>. It deviates from the type signatures of the Applicative function definitions from Haskell but it captures their spirit while making the pattern much more user friendly.

Notes

  1. Applicatives and Functors can expose their data constructors for the purpose of wrapping data as well. Its up to the author of the data type to determine whether they want to expose that functionality or force the user to use pure. The difference between exposed and private data constructors becomes important when discussing IO and other monads in Haskell.

Published

20 Jul 2011

Tags