I just got home from the Elm Workshop hosted by the Milwaukee Functional Programming User Group and RokkinCat.

Having only been introduced to the Elm language a few hours ago, I am going to attempt to give a high level overview and brief introduction of what it is, what's so special about it, and detail out a simple example - so bear with me. By the end of this post I hope to motivate you to research Elm on your own.

Before continuing, here are some key resources that will put you well on your way to becoming an Elm expert!

What is it?

Elm was first introduced by Evan Czaplicki in his thesis, Elm: Concurrent FRP for Functional GUIs which he wrote in 2012.

At its core, Elm is just another functional programming language. There is however one key difference - it compiles into JavaScript. This allows it to be used as a tool that can be used to create web applications. As a matter of fact, the Elm homepage was created using it! But why, amongst all of the other technology stacks that you can use to create your website, would you give any thought to Elm? Since Elm is a functional language, there are no mutable states. If there are no mutable states, how is content ever changed? It turns out that every change results in a new state. If this is beginning to sounds familiar that is because Elm competes with React.js. In fact, Elm outperforms React.js in certain benchmarks.

Why is it so Special?

Elm was already created so that it would be very easy to learn and use. There are many other things that make Elm attractive, like the way it uses a Virtual DOM like React.js. However one of the key benefits in my opinion is everything that it inherits from being a functional language. In addition, Elm was created with:

  • No runtime errors in practice. No null. No undefined 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 also uses a pattern called the Elm Architecture for nesting components. Because of its modularity, code reuse, and testability, the Redux project translates the Elm architecture into JavaScript. This illustrates that even if you choose not to use Elm in a production application, there is still value in implementing its pattern into your application.

Example

The following example is one on the official Elm guide. It reverses a string that is inputed by the user:

import Html exposing (Html, Attribute, div, input, text)  
import Html.App as Html  
import Html.Attributes exposing (..)  
import Html.Events exposing (onInput)  
import String


main =  
  Html.beginnerProgram { model = model, view = view, update = update }


-- MODEL

type alias Model =  
  { content : String }

model =  
  Model ""


-- UPDATE

type Msg  
  = Change String

update : Msg -> Model -> Model  
update msg model =  
  case msg of
    Change newContent ->
      { model | content = newContent }


-- VIEW

view : Model -> Html Msg  
view model =  
  div []
    [ input [ placeholder "Text to reverse", onInput Change ] []
    , div [] [ text (String.reverse model.content) ]
    ]

Let's break this down...

Setup

The first few lines of code import modules that will be used in this app.

  • import Html exposing (Html, Attribute, div, input, text) lets us use the Html, Attribute, div, input, and text functions in our app. Html is the core HTML library for Elm.
  • import Html.App as Html let us use an alias for Html.App.
  • import Html.Attributes exposing (..) lets us use every function from the Html.Attributes module.
  • import Html.Events exposing (onInput) lets us use the onInput event.
  • import String lets us use String, one of the core Elm libraries.

The next line of code acts as the entry point into the application. Every Elm application must have this main value defined:

main = Html.beginnerProgram  
{ model = model,
  view = view,
  update = update }

This code tells the app what the names of your model, view, and update functions are. These three functions form the basis of the Elm architecture. Note that when the state of the app changes, the update function is called which creates a new model which is shown via the view function.

Model

The next thing the code does is create a type alias. Model represents a type and is simply an alias for { content: String }. Type aliases come in handy when your app becomes more complex.

Next, we create a variable model that is initialized to a Model where Model.content is the empty string.

Update

type Msg = Change String is a type constructor. This is common in functional languages. Change is a data constructor and takes a String parameter. Whenever we create a value using the Change constructor, the type of that value is Msg.

Next, we define our update function. But before we do, we declare a type annotation.

update : Msg -> Model -> Model  
update msg model =  
  case msg of
    Change newContent ->
      { model | content = newContent }

Elm will infer types for us, however for readability and to help out the compiler it is best to define type annotations.

Here, we have a type named update that represents a curried function. Note that Msg -> Model -> Model is left associative by default. It be read as a function that takes a function as input and returns a Model. The input function takes a Msg as input and returns a Model.

Next we have a function named update that takes two parameters: msg and model. This function checks the type of the msg parameter and if it is of type Change, it takes the parameter of the type constructor newContent and creates a new model where Model.content = newContent.

View

view : Model -> Html Msg is another type annotation. This time we have a type named view that represents a function that takes a Model as input and returns a value of type Html (which is a type constructor with a Msg parameter).

view model =  
  div []
    [ input [ placeholder "Text to reverse", onInput Change ] []
    , div [] [ text (String.reverse model.content) ]
    ]

Now div and input are simply Elm functions from the Html module that take two parameters:

  • a list of attributes
  • a list of child nodes

So, input [ placeholder "Text to reverse", onInput Change ] [] is the Html.input function that takes a placeholder and onInput function as its attributes and has no child nodes.

Conclusion

Elm is a great functional programming language that allows you to create web applications. I encourage everyone to play around with it and give it a shot and even if you decide not to use it for your project, perhaps you can still benefit from its patterns.

Elm Workshop