I want to wang on about Elm for a bit to cheer myself up. I want to come at it from a different direction and appeal to a different audience than most do.

There are various well-known interfaces for building server-side HTTP apps. A lot of them scream mutability. For example the Java servlet API looks something like this:

void doGet(request, response) throws Error

A bit better in intent is Ruby’s Rack interface. In Elmish that typedef would look like:

call : env -> (status, headers, body)

Pass in an environment and get back a list (that wants to be a tuple) of status, headers and body. In practice, the env is routinely mutated as it goes through apps and middleware and the body coming back is an object that we’ll call each() on to get stuff out of. If you squint though, it looks like it wants to be a pure function and you could write it that way. I have always been secretly in love with Rack for its simplicity.

Typically you use a Rack Builder object to create an app which is composed of many small apps each handling a particular path. A webserver creates this app and handles all the network gubbins to make it serve things, calling your call(env) method again and again.

Elm isn’t (mainly) a server-side language and it doesn’t serve web pages, but I think there are useful parallels with something like Rack. Elm (or more specifically elm/browser) gives you an interface for a JavaScript app that runs inside or on a web page. And it’s instructive to look at it through the same lens as we’ve just looked at Rack. In Rack the webserver handles network plumbing just like Elm’s reactor handles state and event orchestration. And there’s a simple interface that does the work.

The simplest Elm app consists of three functions, that look something like these (I’ve made them a bit simpler still by uncurrying them in places):

init : model
update : (msg, model) -> model
view : model -> Html msg

Elm’s typing insists that all those models and msgs are of the same type, but the reactor doesn’t care what concrete type they are. It’s dealing almost entirely in generics.

Elm also enforces function purity (no side effects) so you can’t mutate things you pass in to functions. You can see that in the update call we pass in one model and get another back. In Java we’d probably write void doUpdate(msg, model) and expect mutation. A whole range of bugs are avoided!

Instead we have an init function that gives us the initial model, an update function that takes the current model and a message and returns us a new model, and a view function that takes a model and returns an HTML thing.

The reactor’s going to take all control away from you from this point. It’ll call init to start with, update whenever it gets a message and view whenever the model changes. It’ll keep track of the model and it’ll update the web page it’s embedded in with any changes to the HTML that comes back from the view. It’s dead simple.

What is this Html msg business though? Well, one way to look at it is that it’s HTML that is msg-y in some way. Just like List String is a typed string-y list and List Int is a typed int-y list, Html msg is a typed msg-y HTML, for whatever concrete type of msg we choose. In practice this means our HTML will be able to attach msgs of the type that our update method understands to the elements it creates. For example, if our message type was

type Event = ClickUp | ClickDown

our view function could look something like

view : Model -> Html Event
view model = button [ onClick ClickUp ] []

and our update function could happily have this signature:

update : (Event, Model) -> Model

All the types would be happy.

There’s not much you can do with this simple model, but you’d be surprised how far it can take you. Typically I use a slightly more advanced version that takes four only slightly more complex functions:

init : flags -> ( model, Cmd msg )
view : model -> Html msg
update : (msg, model) -> ( model, Cmd msg )
subscriptions : model -> Sub msg

What’s different? We pass in some flags to init that let us send in options when the app starts, maybe an initial set of data loaded with the page.

And we have a bit more ability to ask the reactor to do stuff for us with Cmds, which could be anything but are typically things like HTTP requests or maybe scrolling instructions. The reactor takes care of calling these for us and calling update with a msg when there are results. You’ll notice that just like Html was parameterised with the msg type, so are commands. Got to keep that typechecker calm.

We also have subscriptions, which are things like timers or watching other global events like keypresses. That might look something like:

type Event = TickEvent Time.Posix

subscriptions : Model -> Sub Event
subscriptions model =
    if model.updating then
        Time.every 1000 TickEvent
    else
        Sub.none

Again, they send messages to update. And the type checker is happy.

This proves to be a really good model for all kinds of dynamic page apps. The reactor takes care of all the plumbing and you just write a few (or more than a few) pure functions.

If I have one criticism, it’s that it’s not as easily composable as Rack applications are. They practically beg to be composed together like Lego. The types get in the way a bit. You’ll find your Elm update functions might turn into monolithic case statements handling every message.

But I’ve used it and fallen for it in Planedrift, Crunchdown, my crossword app, my standee generator and elsewhere.

So much so that when I reluctantly have to write JavaScript apps, I tend to try to follow the same kind of pattern. In that case, the typechecker is usually looking the other way, which also cheers me up sometimes!