Why Elm?

Those of you who have used Haskell will notice many syntactic similarities between Elm and Haskell, so why Elm? If it looks like a Haskell, well, shouldn’t it just be a Haskell?

In short, Functional Reactive Programming (FRP) does not play nice with laziness, and generating JavaScript is not one of Haskell’s greatest strengths. As Elm grows, it has the freedom to make choices specific to its intended use: functional web GUIs.

In long, Elm began with frustration with current web technology, so the goal was to create a functional programming language for the web that was easy to use and understand. This was not the goal of Haskell, and I suspected that different goals would result in different semantic choices. Functional Reactive Programming (FRP) quickly became the desired model of interaction, simplifying the mental model of GUI programming and providing a more functional way to program GUIs. FRP is fairly young and has some interesting problems, so this choice eventually transformed Elm into my senior thesis.

I considered three ways to create this language:

  • Create a DSEL. It’s generally a good idea because it often saves a lot of work [1]. Unfortunately, producing JS with this method is not really practical because Haskell functions cannot be translated to JS unless you reify everything (i.e. how can (\x -> x + 1) be translated to JS at the source level?). Writing code where everything is reified is annoying and pretty darn close to creating a new language.
  • Get some JS backend working for Haskell. Given the complexity of GHC and my lack of familiarity with it, I did not think this was a tractable project for one person, especially considering that my goal was not Haskell in browsers but “a FP language for the web that is easy to use and understand”.
  • Start from scratch. This gives total freedom over the semantics of the language and avoids the major problems of the other two approaches. The downside is that it requires a lot of infrastructure work (e.g. creating a module system), but this work is generally well understood (i.e. you won’t run into any fundamental problems unless you try to).

I chose the third choice. This allowed me to make the major semantic choices I wanted: Elm is call-by-value and Signals replaces the IO monad as the primary means of interaction with the outside world. Using Signals simplifies the mental model for programmers: a GUI is a time-varying Element, not a sequence of haphazard mutations to a large collection of stateful components. I suspect a truly functional GUI framework will not rely require the programmer to think about the IO monad. Call-by-value is a win for FRP, making it extremely difficult/impossible to accidentally introduce a space leak. More details on these issues and more can be found in my thesis.

The other benefit is that Elm actually works in browsers right now and it’s relatively painless to write client side code (example, examples). Neither would be the case if I chose a different way to implement Elm. AFAIK the Haskell-to-JS projects are not close in terms of ease of use (both in writing code and getting it running).

So why do modules look the same? Well, I just wanted to add a dead-simple system to make it possible for people to work on larger projects with less hassle. Haskell has this and it works, so I don’t see a great reason to do something else right now. In some ways I prefer the ML module system [2] because functors could make it easy to create more flexible GUI libraries (e.g. the color scheme is passed in as a module), but I do not expect this to be incompatible with dead-simple modules.

So why does the syntax look the same? You have to make a lot of syntactic choices when you are designing a language. Haskell’s syntax is quite nice when compared with other FP languages I’ve seen, and I didn’t see any point in arbitrarily inventing new reserved words or idioms. Why change the parts that aren’t broken?



Comments are closed.