Update (Sept. 2015): We now offer two video courses on Elm: an introduction to Elm where you learn how to build reactive web apps step-by-step and a signals tutorial that goes in-depth into Elm signals, mailboxes, and ports!

Around this time of year I tend to go looking for something new to learn in the spare moments between holiday activities. It's a way of stepping back and getting a different perspective. This year the Elm language caught my eye. So on a whim one afternoon I cracked open the laptop and started writing some Elm code, not really expecting my interest to outlast a log on the fire.

Well, it's been a week now and I'm still having fun with Elm. Turns out this journey has been an unexpected gateway into functional programming, but with a graphical twist. I think the graphical part has been the key for me. That or the steady intake of sweets that keep finding their way to my desk. In any event, the whole experience has been so enjoyable and enlightening that I couldn't help but share.

If you've been wanting to try functional programming (FP), I'd encourage you to give Elm a whirl! Here's how I got started...

Try Elm

The easiest way to get started with a quick win is by using the interactive online editor. Here's every newbie's favorite first program, Elm style:

import Graphics.Element exposing (..)

main = 
  show "Howdy world!"

Type that code in the left-hand pane of the online editor, hit the "Compile" button (or use the keyboard shortcut CTRL-RETURN), and the output magically appears in the right-hand pane. For a peek behind the scenes, view the source in the right-hand pane and you'll see that the Elm code got compiled to a potent mix of HTML, CSS, and JavaScript.

Cool! So that works, but why?

Well, I don't know about you, but the syntax of this line really threw me at first:

main =
   show "Howdy world!"

When I see an equal sign (=), I think "assignment". But what actually happened here is we defined a function. The equal sign separates the function name from the function body. In this case, the name of the function is main and the body of the function calls another function: the built-in showfunction. The show function takes one parameter, the string "Howdy world!" in this case, and turns it into an element that can be displayed in the browser. The main function is automatically called when the program runs which is why we see "Howdy world!" in the browser.

OK, so let's look at another function. Suppose we'd like to greet people by name. To keep the code tidy, we'll define our own function named greet. Change your program around in the online editor to look like this:

import Graphics.Element exposing (..)

greet name = 
  "Howdy, " ++ name ++ "!"

main = 
  show (greet "Mike")

Notice that unlike the main function, our greet function takes one parameter named name. The parameter follows the function name. The body of this function returns a concatenated string including the person's name. In the main function we then call the greet function and pass it a name. The resulting string is then passed to the show function as before. So you can think of a function as a way of replacing (or reusing) code.

Go ahead, give it a spin by punching CTRL-RETURN for a greeting.

Functions, Functions, Functions!

Functions are the bread and butter of any functional language, and right off the bat we're introduced to our first Elm function. It can feel a bit weird and disorienting at first. And the number of functions and parentheses only increases from here. I'll be the first one to admit that I've struggled with functional programming, both in terms of syntax and the underlying principles. I've had to come at it from different angles. What attracted me to Elm, and what finally helped make functional programming "click" in my brain, was using functions with Elm's graphics library so I got quick, visual feedback.

So let's try some functional programming in the context of making a simple graphics program. Now, you can certainly create fairly sophisticated games with Elm, but we're learning language fundamentals so we'll keep it simple. You know, like displaying a blue square. To do that, start fresh in the online editor with the following code:

import Text exposing (..)
import Color exposing (..)
import Graphics.Element exposing (..)
import Graphics.Collage exposing (..)

main = 
  collage 200 200 [ filled blue (square 100) ]

Get some instant gratification by hitting CTRL-RETURN and a blue square should appear!

Now that we have some graphical feedback, let's unpack the code. First, we needed to import a few more Elm libraries. Then we changed the body of our main function to call the collage function. You can think of a collage in Elm as a canvas for drawing freeform graphics. The collage function takes three parameters: the width (200), the height (200), and a list ([ ]) of what Elm calls forms to display within the collage. To create a form inside the collage list, we called the filled function passing it a color (blue) and a shape. What's the shape? Well, we wanted a square, so we called the square function with a size of 100. The resulting shape was substituted in as the second parameter to the filled function. So we end up with three functions in all: main calls collage which calls filled which calls square.

Yeah, but squares are kinda boring, you say. OK, let's twist it around to be a diamond:

main = 
  collage 200 200 [ rotate (degrees 45) (filled blue (square 100)) ]

More functions! The rotate function takes two parameters: the angle in radians and a form. Using the degrees function we convert 45 to radians which fills in the first parameter. And we already have a form being returned by the filled function which fills in the second parameter.

This is getting hard to read, so let's tidy things up by creating a new function that creates the diamond:

diamond color =
  rotate (degrees 45) (filled color (square 100))

Our diamond function takes one parameter named color and the body of the function is the same series of function calls we had before in the collage list. Then we replace the messy code in the collage list with a call to our diamond function and specify a color:

main = 
  collage 200 200 [ diamond blue ]

So again, we've used a function to replace (or reuse) code. Creating colored diamonds just got a whole lot easier. And that reminds us that we'd also like to create diamonds in various sizes—the bigger the better! So let's change the diamond function to take a second parameter named size:

diamond color size =
  rotate (degrees 45) (filled color (square size))

Now we can specify a color and size when creating the diamond:

main = 
  collage 200 200 [ diamond blue 100 ]

(Old habits die hard, and instinctually my fingers want to type a comma between the parameters.)

Just for kicks let's use our handy diamond function to add a slightly smaller red diamond to the collage list:

main = 
  collage 200 200 [ diamond blue 100, diamond red 75 ]

Notice that the items in a list need to be separated with a comma. Now our collage has two forms. By default, forms in the collage are oriented at (0, 0) so the red diamond appears inset in the larger blue diamond. It's crazy stuff, but hey, we're pulling out all the stops!

What, you don't like those diamonds? Well, this would be a great time to start tweaking the code to suit your fancy and showing it off by posting the code on share-elm and sharing the link.

Function Pipes

OK, so defining the diamond function gave us a way to easily create diamonds and cleaned up the code for creating the collage. But the diamond function itself is still a bit hard to read:

diamond color size =
  rotate (degrees 45) (filled color (square size))

The parentheses get in the way, for starters. Plus you have to start with (square size) and read from the inside out, replacing the results stepwise until you've reduced it down to the final call to rotate. Thankfully, there's an easier way using the pipe operator (|>):

diamond color size =
  square size |> filled color |> rotate (degrees 45)

The |> operator pipes the result of the function on its left into the last parameter of the function on its right. If you've ever piped multiple commands together in the Unix operating system, this will make sense. If not, think of it kinda like that game where one person whispers a story to another, which is passed through a line of people until the last person announces the final message. In retelling the story, it inevitably changes. In the same way, each function can transform what it's given and pass something entirely different to the next function in line.

So the shape that the square function returns becomes the second (last) argument to the filled function. And the form returned by the filled function becomes the second (last) argument to the rotate function which returns a rotated form.

You can also write this on multiple lines which makes it read more like a list of steps:

diamond color size =
  square size
    |> filled color
    |> rotate (degrees 45)

Type Annotations

As I started looking at other Elm functions in the wild, I immediately bumped into a strange incantation that threw me at first. Here's an example:

add: Int -> Int -> Int
add x y = x + y

We recognize the second line as defining an add function that sums two numbers, but what's the line before it? Well, Elm is strongly typed and every definition can be preceded by what's called a type annotation. Before we unpack it, by comparison here's how our diamond function looks with a type annotation:

diamond: Color -> Float -> Form
diamond color size =
  square size
    |> filled color
    |> rotate (degrees 45)

The annotation says that the diamond function has a type of Color -> Float -> Form. In simplest terms it means that diamond takes two parameters—a Color type and a Float type—and returns a Form type. Notice that each parameter is separated with -> and there's nothing special indicating that the last item is the return type. Since Form is the last item, it's implied to be the return type.

Strictly speaking, you don't need type annotations because Elm supports what's called type inference. That means the Elm compiler can verify your program is type-safe without any type annotations. However, it's considered good practice to add type annotations to top-level definitions in your program. Consider type annotations to be a handy thing Elm's compiler does to make your life easier.

Install Elm

The online editor was so convenient and stable that I didn't bother to install the Elm Platform on my own machine until I had a reasonably-sized program. And even then, it wasn't much of a bother to get everything installed. I used the handy Mac installer (there's also a Windows installer) and with a couple clicks it laid down all the required files. Of particular note, you get a handful of command line tools: elm-repl, elm-make, elm-package, and elm-reactor. (On a Mac they live in /usr/local/bin/).

Let's see what each of those tools does for us...

Experiment In The REPL

The Elm read-eval-print loop (REPL) lets you experiment with Elm expressions and get instant feedback. Fire it up using the elm-repl command:

$ elm-repl
Elm REPL 0.4 (Elm Platform 0.15)
  See usage examples at <https://github.com/elm-lang/elm-repl>
  Type :help for help, :exit to exit
>

Once it starts, you'll see a prompt where you can enter any Elm expression and get the result. For example:

> import String
> import List

> name = "Mike"
"Mike" : String

> "Howdy, " ++ name ++ "!"
"Howdy, Mike!" : String

> "Howdy, " ++ String.toUpper name ++ "!"
"Howdy, MIKE!" : String

> names = ["larry", "moe", "curly"]
["larry","moe","curly"] : List String

> List.map String.toUpper names
["LARRY","MOE","CURLY"] : List String

> List.filter (\n -> n < 0) [-2..3]
[-2,-1] : List comparable

> List.foldl (\n sum -> sum + n) 0 [1..6]
21 : number

> List.foldl (+) 0 [1..6]
21 : number

When you're done, exit the REPL by typing :exit.

A good REPL is one of the first things I look for when trying new languages. After nearly 10 years of using Ruby, I still reach for Ruby's REPL (irb) all the time. But I must admit that I haven't spent much time in Elm's REPL yet. I think it's because I'm more focused on getting graphical feedback as I learn Elm.

Make an Elm Project

While the online editor and the elm-repl are good interactive environments,you'll soon want to save your code in Elm source files and organize them in projects.

  1. Start by creating a directory for your Elm project and changing into it:

    mkdir my-elm-project
    cd my-elm-project
    
  2. The convention is to have a Main.elm file in the root of your project directory. Create that file and paste in our graphics code as a starting point:

    import Text exposing (..)
    import Color exposing (..)
    import Graphics.Element exposing (..)
    import Graphics.Collage exposing (..)
    
    diamond color size =
      square size |> filled color |> rotate (degrees 45)
    
    main = 
      collage 200 200 [ diamond blue 100, diamond red 75]
    
  3. Then to compile the Main.elm file and embed the output in an index.html file, use the elm-make command like so:

    elm-make Main.elm --output index.html
    

    It automatically installs any necessary Elm packages, in this case elm-lang/core.

  4. Finally, run the program by opening the resulting index.html file in your favorite browser!

Develop In The Reactor

Using elm-make gets the job done, but running it after every change slows down the feedback cycle. Ideally you want something more interactive along the lines of the online editor running on your machine. That's where the Elm Reactor comes in.

  1. While in the root of your Elm project directory, start the reactor using

    elm-reactor
    
  2. Then navigate to http://localhost:8000 in your browser and you should see a navigation pane listing the files in the project directory.

  3. Click on the Main.elm file to run it.

  4. You prefer purple diamonds over blue diamonds? Make the change by opening the Main.elm source file in your favorite editor. (I use SublimeText with Elm syntax highlighting.)

  5. Then refresh the browser to compile and re-run the program!

The Elm Reactor has two very interesting features that I've yet to explore:

  • First, it has time traveling debugger. To get a peek at the debugger, click the small wrench icon to the left of the Main.elm file listed in the navigation pane. Then check out the videos in Time Travel Made Easy to see a quick demonstration of the debugger in action.

  • The Reactor also supports hot-swapping: swapping new functions and values into a program while it's running. Check out the videos in Interactive Programming to see examples of hot-swapping in action. It's worth noting that the online debugger also supports hot-swapping.

These two features are still fairly young and tender, but I love the innovation that's happening on the interactive programming front. Very cool stuff, indeed!

Install A Community Library

At some point down the line you may want to fetch packages from the Elm Package Catalog. Rounding out our tour of the command-line tools, the Elm package manager makes it really easy to share and use packages.

For example, perhaps you're itching to write some unit tests. The Elm-Test package gives you a practical unit testing framework. To install that package, run:

elm-package install deadfoxygrandpa/elm-test

(Yup, that's the real package name!)

As a starting point, here's a quick example of unit test suite you can put in a file called ExampleTests.elm, for example:

import ElmTest exposing (..)
import String exposing (..)

tests = suite "My Test Suite"
        [ test "Addition" (assertEqual (3 + 7) 10)
        , test "String.reverse" (assertEqual "ekiM" (String.reverse "Mike"))
        , test "This test should pass" (assert True)
        , test "This test should fail" (assert False)
        ]

main = 
  runDisplay tests

To run the tests, click the ExampleTests.elm file in the reactor and you should see green for passing tests and red for failing tests.

Continue Learning

That's a really good start, but there's so much more to Elm and I hope you continue digging into it. As with learning any new programming language, reading lots of example code is invaluable. Here are a few starting points:

Summary

I don't have any big plans that involve Elm. All I know is that I'm having fun and learning new ways of programming. Elm even has me reconsidering old ways of programming. But what has surprised me most while learning Elm is how it has sparked a interest in learning more about functional programming in general. Suddenly languages such as Elixir and Haskell feel more within reach. And if that's all I take away from this adventure, then it will have been very well worth it.

In our Elm video tutorial, you'll learn how to create a single-page, reactive web app from scratch so you see how everything fits together and can start experimenting on your own!