The Hang of Elm: Hangman and functional programming with Elm
One of my favorite ways to introduce (pure) functional programming is to use an example of imperative functional programming. I like using hangman because it’s simple and very effective in showing some of the best features of functional languages.
Hangman is a game in which “someone tries to guess the letters of a word, and failed attempts are recorded by drawing a gallows and someone hanging on it, line by line” (Oxford Dictionaries).
A program to play hangman is easy to write as a command-line application, but it’s just as easy to write as an HTML application with a functional programming language such as Elm.
All applications in Elm follow a basic pattern that consists of a model to describe the application, a way to view the model, and a way to update it given an action.
The model of each game of hangman should include at least the letters of a word and whether they’ve been guessed or not, and the number of failed attempts.
If we ignore failed attempts, the model is just a list of characters and booleans:
The model of a hangman game is initialized by setting all the letters of the word as not guessed:
Strings in Elm are not lists of characters, unlike strings in Haskell. For that reason, given a string, we have to transform it into a list and then map a function that creates tuples with the guessed value set to
In order to define how to update the model, we need to define what an action is. In this case, a character is enough – it represents that the player pressed a key or made a guess:
When the player makes a guess, the list of letters and guessed values has to be updated if there’s a match:
To update the list, we map a function over each letter and set its guessed value to
True if it matches the guess or if it has already been guessed.
Every time the model is updated, a new model should be displayed to the player, but we haven’t defined what the model would look like in HTML:
This is basically an HTML document inside Elm. The
toString function turns the word into a string with hyphens for unguessed letters:
Again, a string is not a list of characters, so we map a function over the letters to choose the letter or a hyphen, and then build the corresponding string with a fold.
But the most important part of the
view function is that it takes an address and creates an event that reports to that address. If the player presses a key inside the input, that’s reported to the given address and used for updating the model.
All applications in Elm follow the model/view/update pattern, which is actually known as the Elm architecture. The nice thing about it is that the three components are pure and completely separate – we haven’t done anything to connect view and update.
And that’s it. The StartApp package allows us to start an application by simply saying what model, view, and update are. To see it in action, get the code, and paste it and compile it in the Elm online editor.
This hangman game is very basic, though. We’re ignoring failed attempts and nothing happens if the player wins. Let’s take a look at the model if we were to extend it:
Instead of just a list of letters and guessed values, we include a status that says whether the game is over (lost or won) or in progress with a number of lives:
Even though Elm is just in version 0.15, I think it’s excellent for showing the best of pure functional programming – basically, fewer headaches thanks to a clean separation of pure (model/view/update) and impure (