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...
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
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
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:
collage which calls
filled which calls
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))
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
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.
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)
|> 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)
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.
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-reactor. (On a Mac they live in
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 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
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.
Start by creating a directory for your Elm project and changing into it:
mkdir my-elm-project cd my-elm-project
The convention is to have a
Main.elmfile 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]
Then to compile the
Main.elmfile and embed the output in an
index.htmlfile, use the
elm-makecommand like so:
elm-make Main.elm --output index.html
It automatically installs any necessary Elm packages, in this case
Finally, run the program by opening the resulting
index.htmlfile in your favorite browser!
Develop In The Reactor
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.
While in the root of your Elm project directory, start the reactor using
Then navigate to http://localhost:8000 in your browser and you should see a navigation pane listing the files in the project directory.
Click on the
Main.elmfile to run it.
You prefer purple diamonds over blue diamonds? Make the change by opening the
Main.elmsource file in your favorite editor. (I use SublimeText with Elm syntax highlighting.)
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.elmfile 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.
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:
Learn how to build a reactive web app with Elm, step-by-step, in our video tutorial!
Create more reactive Elm apps by mastering signals, mailboxes, and ports in our in-depth tutorial!
Jump in the REPL and follow along with this walkthrough of the Core Language.
The official Documentation page has links to more in-depth Elm documentation.
Bookmark the documentation for the Standard Libraries. Better yet, take the time to skim through the documentation so you know what's possible. I make a habit of doing this with any new language. Seeing how Elm defines functions was also a valuable way to cement what I had learned.
Work through some of the Elm Examples using the online editor.
"Elm By Example" is a free, 15-chapter online book.
"Learning FP the hard way: Experiences on the Elm language" is a great introduction to using Elm to create the base for a Space Invaders type of game.
"My adventure with Elm" is an insightful set of slides from a talk introducing Functional Reactive Programming and Elm.
PewPew is an impressive space shooter game.
And of course the Elm mailing list is a good place to track Elm development and see what folks are up to.
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!