What is elm?

and why am I using it?

elm (it is always a lowercase e, apologies, pedants and e e cummings haters) is "a delightful language for reliable webapps", according to the official website.

For me, elm is the answer to the following series of questions:

  1. Can't we write just reliable webapps in javascript?

Yes, but it is hard. undefined is not a function, we hear.

It's hard enough that a great deal of effort has been expended creating build pipelines for javascript webapps to make things easier.

  1. Wait, build pipelines?

  2. Isn't javascript interpreted?

  3. If we're going to preprocess our javascript, why don't we write in a language that compiles to javascript, but hates freedom less/kills fewer kittens, etc?

  4. What would we want that language to look like?

Author's note: A bucket list of language features was removed from here. Suffice to say: elm is a good fit for me.

So, about elm...

It's statically and strongly typed. Moving between types must always be explicit, there is no coercion.

It doesn't just prefer immutability - it requires it. Unless we start writing native modules, elm won't allow mutation at all.

How the hell do we write a webapp where anything changes, then? Well, elm isn't really just a language. It also provides an architecture (although I'd be more tempted to call it a runtime) and an excellent standard library.

Behind the curtain: the elm architecture

elm grandly claims we can write a whole webapp with only four ingredients:

You'll note that the return type of view is parameterized by our event type. This means that our resulting Html has hooks within it to trigger 'Msg' events based on user interactions, like a mouse click.

Under the covers, elm is running an event loop something like this:

var model = initialModel;
var currentView = view(initialModel);
applyToDom(currentView);
while (true) {
    var event = events.poll();
    model = update(event, model);
    var newView = view(model);
    applyDiffToDom(diff(currentView, newView));
    currentView = newView;
}

I've represented that in terrible javascript pseudocode in the spirit of comprehensibility. I suspect that in reality there is not a queue, but a callback; this isn't going to be too important for this discussion though. Events turn up in the queue when events that trigger Msgs occur.

We've used some functions I haven't defined: applyToDom, diff and applyDiffToDom. The first of these takes the elm representation of our view and makes the DOM reflect it. The second, diff takes two elm view representations and computes the differences between them. The third, applyDiffToDom takes the resulting diff and applies it to the real DOM.

Whence events? Well, the Html return type returned from view has event sending attributes buried within it. This demo from the official documentation is the easiest to follow example.

Convinced? Good. Let's build something with elm.