Elm, First Impressions
I like exploring new programming languages and paradigms in my spare time. Here are some of my thoughts on Elm.
Elm is a purely functional, strongly typed language for web development. It’s a very opinionated language, with a very powerful run-time that is designed to make writing web applications easy. There are some things that I really like about Elm, and some things that I find frustrating. Your mileage may vary.
The Elm Architecture
All Elm applications are written with the same general design pattern. The general structure is similar to things like Redux and Flux (which is actually based on Elm):
model: A single object, encapsulating the entire state of the application.
update: A pure function that takes a message and a model and produces a new model.
view: A pure function that takes a model and produces instructions on how to render the application.
This pattern is called “The Elm Architecture”, and the run-time supports it
directly. Once you specify these three components, the run-time sets up a model
and renders a view. Then, it listens for messages from the view, passes each
one to the
update function, changes the model accordingly, and re-renders only
the parts of the view that changed.
I really like this approach because it manages abstraction in a really intelligent way. On one hand, I have access to (and am expected to deal with) all of the application-specific parts of my project. As a programmer, I need to specify the application state, how that state changes, and what that state “looks like”. On the other hand, machinery that is especially general (the wiring) is taken out of the programmer’s control completely. (There isn’t a lot of configuration in Elm; in general, if the run-time want’s to handle something, you’re expected to let it.)
A nice side effect of this is that Elm is actually really fast. In some sense, the Architecture encompasses all of the slowest parts of the application—this makes it free to heavily optimize those pieces.
The other major benefit of Elm is that it is statically typed. This means that the compiler (and not the Chrome developer console) catches your mistakes. I could go on for a long time about the benefits of a good type system, but I’ll leave that for another blog post.
No Type Classes
Since Elm looks so much like Haskell, I often expect it to behave like Haskell. While it does most of the time, sometimes it falls short. One large place this happens is with type classes; since Elm does not support type classes it misses out on some of the really nice features that come along with them.
For example, rather than use
do notation to deal with monads, we need to
explicitly bind arguments into monadic functions (in Elm, most types define a
andThen for this purpose). Keep in mind that this problem
is related to type classes because Haskell’s
do is tied to the
class; anything that implements
do notation would be a nice to have, but in the end, it isn’t such
a big deal. One thing that is a big deal is how Elm deals with comparisons. In
Haskell, we have
Ord a which allows a user to define comparisons for their own
types. Elm uses something called
comparable, does the same job as
without being a proper type class. Basically, a function
can take any argument at all, but a function
can only take an argument that permits comparisons. Unfortunately, the only
types that are
that’s it. There’s no way to make a user defined type comparable, since
comparable is just a built-in language construct and not a formal type class.
This is especially frustrating since the built in type
Dict (a dictionary
based on a balanced binary tree) has the following interface:
The result is that no user defined types can ever be the key of a dictionary, even if there is a perfectly reasonable way to compare them.
Overall, I really like Elm. It’s been fun to work with, and it’s definitely mature enough to be usable for some projects. It has some drawbacks, and I’d hesitate to put it into production just yet, but it’s certainly heading in the right direction.