My Elm adventure
On Sunday, 8th of May 2016, I started reading about Elm. I was interested because of its functional reactive programming nature and it’s one of the inspirations (though not primary) for ReactiveCocoa and Redux. I started reading about its syntax, its architecture, looking at a few examples, and watching several awesome videos about Elm. I especially like the concept of signals and mailboxes. It’s not a foreign concept if you’re coming from ReactiveCocoa or other FRP frameworks. In Elm, signals felt natural and it fit nicely with the language (I believe it’s due to the fact that Elm is functional rather than imperative). Elm signals did not feel bolted-on like in ReactiveCocoa.
Well, on Tuesday (10th of May 2016), signals were removed from Elm with the post titled A Farewell to FRP. I was completely surprised and dumbstruck. But not for long, the more I read and internalise the post and the discussion on Elm slack channel, it became clear that subscriptions in Elm 0.17 was actually a really big deal and it simplified a lot of things. Rather than setting up the signals wiring, subscriptions let our components sit around and wait for messages, whether it’s from WebSocket, the clock, etc. And it becomes the underlying library code’s responsibility to handle a bunch of tricky resource management stuff behind the scenes (e.g. WebSocket connection). I think it’s a win for users.
Our team used IdeaBoardz to conduct our retros and I thought that its UI could be improved . Thus, I decided to spend the following week after my learning to build Elmütt that is a fresh clone of IdeaBoardz written in Elm. It uses Elm 0.17 and Bootstrap 4 for the front end; and Python 2.7, Flask, Redis, and WebSocket for the back end. And it is deployable to Heroku.
I am really happy with Elm
and it is such a breath of fresh air. Below is my notes that I took whilst learning about Elm. I think you should try Elm.
Elm
This text file describes the Elm programming language, specifically version 0.17. It was designed by Evan Czaplicki to provide “the best of functional programming in your browser”. Elm is about:
- No runtime errors in practice. No
null
. Noundefined is not a function
. - Friendly error messages that help you add features more quickly.
- Well-architected code that stays well-architected as your app grows.
- Automatically enforced semantic versioning for all Elm packages.
Elm is functional, no state and no side effects. Elm is a strongly typed language with static typing, similar to Haskell and other ML inspired languages.
Getting Started
Install the necessary software:
brew install elm
npm install -g elm-server
npm install -g watchman
And create a simple project:
mkdir elm
cd elm
elm package install
elm package install elm-lang/html
touch Main.elm
Edit the file Main.elm
to contain the following code:
module Main exposing (main)
import Html
main = Html.text "Hello World"
Compile the file: elm make Main.elm
and open the resultant index.html
. Alternatively, run elm reactor
and go to http://localhost:8000
. Unfortunately, it doesn’t support live reload. To get the live reload functionality, install elm-server
and run elm-server Main.elm
.
The Elm Architecture
The Elm Architecture is the recommended pattern for building Elm applications. It’s a unidirectional architecture that consists of three components: - Model is a type defining the data structure of the state. - View is a function that transforms state into rendering (e.g. HTML). - Update is a function from previous state and an action to new state. An action is a type that encapsulate a user action or an external event.
In code, it looks like the following:
module Main exposing (main)
import Html
import Html.App
main : Program Never
main =
Html.App.beginnerProgram
{ model = "Hello, world!" , view = Html.text , update = identity }
Or, in the expanded form:
module Main exposing (main)
import Html exposing (Html, text, div)
import Html.App
type alias Model = String
model : Model
model = "Hello, world!"
view : Model -> Html Msg
view model =
div [] [ text (toString model) ]
type Msg = NoOp
update : Msg -> Model -> Model
update msg model =
model
main : Program Never
main =
Html.App.beginnerProgram
{ model = model
, view = Html.text
, update = update
}