How I (Finally) Built an App in Elm

aspittel profile image Ali Spittel ・4 min read

Two years ago, I was asked by a company I was working for to learn Elm — a functional front-end programming language. I found the syntax strange and the functional programming paradigm difficult. We ended up moving to other front-end frameworks and eventually all but forgot about Elm.

I recently taught a lesson on Redux and was asked a bit about Elm by my students. It prompted me to think about Elm and see if now, two years further into my programming career, the pieces would fall into place and I could figure it out.

The Learning Process

I decided to start with the documentation. Elm is pretty well known for their documentation, and many technologies with higher barriers to entry have to so that people use their tools. I started at zero with the tutorial on their website and quickly progressed through the more standard parts of the language. There were some interesting syntactical choices — like the pipes for changing record attributes. I also found it interesting that their standard collection is a linked list instead of an array. It somewhat makes sense with a front-end language; however, it made my final project more tricky!

Elm Hello World

module Hello exposing (..)

import Html exposing (text)

main = 
    text "Hello"

From there I moved through the “Elm Architecture” portion of the tutorial. I felt like it jumped from 0–100 really fast in this part. I definitely got a little bit lost here. Overall, though, the design pattern of model, update, view, subscriptions made sense. I like the ability to know where everything is situated.

Throughout the learning process, I continuously went back to the sample code in the elm-architecture-tutorial.

The other really nice features include the error messages and time traveling. In Elm’s compiling process it makes sure that there won’t be any runtime errors. This process means you have really good, clear error messages before your code runs. I also really like the “time travel” functionality where you can see your application’s state at various points. These parts of the development experience are great, and I can see why other tools (such as Redux) have built off of these ideas.

After looking through the “Elm Architecture” portion of the tutorial, I was able to step by step walk myself through the code, but I was still really struggling to write my own Elm code from scratch. I ended up looking at some other projects that I found on Github such as Flatris and Elm Hanoi.

From there I found Tensor Programming’s Elm tutorial which ended up helping a lot. I really like the follow along style of learning, so this tutorial was really helpful for that.

The Final Project

I originally wanted to build Towers of Hanoi in Elm since it is a pretty easy JavaScript game to write; however, I found it still a bit out of my league in Elm. I instead scaled down and wrote a trivia app, which was still pretty tricky.

I ended up using create-elm-app which is very similar to create-react-app. It was very helpful for both development and deployment. There were still a few things that I had to figure out in my code. First was the linked list vs. array issue. I ended up using the linked list and iterating through it to retrieve different questions. In other languages I would have kept an index value and used that to move from question to question. The architecture of the program was a bit different in Elm.

I also found working with “maybes” difficult. Maybes are a datatype in Elm similar to a string, integer, or list that can be “Nothing” — similar to null or None in other languages — or have a value. In order to work with the value, if it exists, you must take it out of the maybe. It makes sense from a strictly typed perspective and a functional perspective, but it makes the code somewhat clunky.

Example Maybe Handling

currentQuestion : Maybe Question -> Question
currentQuestion question = 
    case question of
        Just question ->
        Nothing ->
            { question = ""
            , answers = []
            , correctAnswer = ""

Eventually, I did come up with a MVP trivia application that asks questions, lets users click buttons with the different answers, and then keeps track of how many questions were answered correctly. Deploying the application ended up being pretty easy — I just had to run elm-make and push the build subdirectory to the gh-pages branch of my remote repository. The code is here and the app is deployed here.

What Comes Next

It turns out Elm didn’t get much easier in the past few years — Elm was still a totally different way of thinking. Even though I produced an MVP, getting there was 100x harder than if I had built it in a language I was more comfortable with. The design patterns were still difficult and working with data seemed much trickier than it should be. I still wouldn’t choose to use Elm, though I do see some of the benefits of it — like static typing and tough error catching. If I were to utilize functional programming on the front-end, I would much rather use React and Redux since they are both still in JavaScript. Overall, I think Elm is a good idea, but some of the syntax and implementation is still a bit rocky.

Part of my "On Learning New Things" series.

Posted on by:

aspittel profile

Ali Spittel


Passionate about education, Python, JavaScript, and code art.


markdown guide

It took me a couple of tries at F# (my first FP language, similar to Elm) before I could write in it, and a bit longer before I was writing using functional idioms. So don't feel bad. Elm (and FP)'s learning curve is harder compared to something like JavaScript, but it is worth learning. This is kinda the way I look at it in graphs.

Writing your first pure JS app is about like this. Super easy to start, but increasingly hard to recover from mistakes.
x squared graph

Writing your first Elm app is kinda like this (assuming no prior FP knowledge). Pretty hard to get started... maybe even have to "unlearn" some habits. But recovering from beginner mistakes (or changing requirements) is not particularly hard. Just normal work.
log x graph

Also note that there are built-in helpers for Maybe. Totally optional to use, but a little shorter.

blankQuestion =
    { question = ""
    , answers = []
    , correctAnswer = ""

currentQuestion : Maybe Question -> Question
currentQuestion possibleQuestion =
    Maybe.withDefault blankQuestion possibleQuestion

-- or if you prefer

currentQuestion possibleQuestion =
    possibleQuestion |> Maybe.withDefault blankQuestion

We use Elm in production, and I am very happy with that choice. In fact, we trained two devs without prior professional experience (but with CS education) to use Elm. They were writing in it after a couple of weeks and doing features after a month. I think immersion and going through the learning process with others helps. After 1 month, this was obviously not the greatest Elm/FP code, but Elm is quite amenable to refactoring once you learn a better way.


Ah okay! I gave myself probably around 10 hours in total -- I'm not learning it for a job so it makes it harder to justify a huge time commitment! I do have Redux experience, though this was my first fully functional language. I was just proud that I had something working at the end! Maybe someday I will have more time to commit to learning FP more fully!


If you do get to the point that you want to make another attempt at an FP language, and you have some interest in .NET, then I highly recommend F# and The Book of F# by Dave Fancher.

F# is essentially OCaml for .NET, created by Don Syme of Microsoft Research Cambridge.

Unlike Elm, it isn't a pure FP language. (To be a first-class .NET language, it has to support .NET's OO paradigm.) But like Elm, it puts FP front-and-center.


So much this - I think I've tried to dig into Elm three or four times now, over the course of several years. I love the ideas behind it, and the guarantees it provides. I thought after getting heavily into functional-style JavaScript programming the transition would be easier but it was always difficult.

I want to like it, but I'd take TypeScript's semi type-safety over Elm any time.


This is how I feel. I understand the performance boosts in the final products but the process of building and typing out all of the [ ][ ] in code just cripples me. I really love the idea of functional programming, it just seems to run circles around OOP, but the syntax is absolutely awful and as a person who specializes in CSS this is the greatest downfall. My experience with CSS in elm has not been good. I wish there was a lot more info and tutorials about it. If it had the same type of hype and following as Vue (which just feels good) I think more would be done with it.

I do have to say though that a truly remarkable project is Dscova.com I really wish these guys would put more information out in actual code so we could learn how to build things as good as this.


Js functional style really doesn't feel the same for a variety of reasons...I think no matter how good you get at it. Elm/purescript a lot closer to Haskell. So if you are trying to learn that style, go for it. That being said, elm has so many breaking changes even today, that using in production beware.


I love this walkthrough -- definitely something I'll be referring back to if I ever take a stab at Elm.


Thanks for the article i really liked it :D
I started using Elm 0.18. In the process i got used to functional coding. I really like the compiler errors but still hate the documentation of elm packages. I think the documentation is not updated(some packages updated but not their documentation) and not complete(eg. http v1.0.0 package).
Being a new language creates lack of examples and most examples are for older versions of Elm. And because Elm is still in like alpha development(0.18) features change dramatically. This causes the examples found on net are not 100% compatible with the version used.
All in all Elm is a good and fun language but using it for a live project is a hard decision to take. I believe ELm will grow and be a very nice language for frontend.


Yeah, the packages are really rough to deal with from what I noticed! I was trying to use a random number generator package and I couldn't get it to work!


I think the ideal would be a combination of JS style docs, where most of the documentation for a lot of libraries is in the README with a few examples, and the Haskell style, where types are often all you're given.

I found that as I got better at reading type signatures, I much much much preferred Elm's package repository and documentation to what can normally be found on NPM, but that was totally because I learned to read the type signatures (which took practice).

As much as I love having type signatures in the documentation, the presence of helpful types in Elm's package documentation can make it more difficult for package authors to remember to write out good examples. And examples are definitely needed in many cases to make sense of how the libraries are intended to be used. That's a way in which the community can improve.


I know it can be hard but if you are interested just have a look in elm-slack - I'm sure you'll find people helping you get over the first blockers.

Just to give you some outlook: the little snippet you gave can be written as

currentQuestion : Maybe Question -> Question
currentQuestion = 
        { question = ""
        , answers = []
        , correctAnswer = ""

and you can find many of these little things that makes your life easier here package.elm-lang.org/packages/elm-...

You'll probably not believe me but it's really a lot easier than react/redux and quite safer too


Awesome, thanks! I think it depends on the developer -- for me I've been a React/Redux dev for a couple years professionally so it is much easier!


I've always thought that Elm was an excellent programming language! Strong type safety, helpful compiler messages, good community, great tools! What more could you ask for in a programming language?

In 32 lines or less of code I was able to write a crappy little app with horrible styling that communicated with Github's REST API to check how many followers a user has. It's not impressive by any stretch of the imagination, but the power you have with relatively little code is awesome!


Ah cool! I definitely think it depends on the project and which data structures you need for it!


Really honest take. Great great post.


Great article!

What version of Elm?

I see the current version is 0.18, which has undergone a significant amount of change since I originally looked at Elm.

For example, I was surprised to find out Elm got rid of FRP when 0.17 came out.

For those who are considering Elm for anything, one big caveat is that Elm is undergoing rapid evolution from release-to-release. It's both a good thing, and bother to absorb those changes.


I used the current version for this! I definitely agree -- I kept finding libraries that were now incompatible.


Great post I can totally relate!

I think It can be difficult to learn functional programming because a lot of time people are also learning advanced statically-typed functional programming. So they are really learning two things at once: Functional programming, and an advanced type system. Elm isn’t super advanced when compared to something like Haskell however it is still a massive change from JavaScript or python.

I think of learning functional programming like the experience of learning to program for the first time rather than the experience learning a new programming language. It takes a lot of time and dedication but I think it pays off in the end.


Yeah! I have quite a bit of Java and C++ experience, so that wasn't really the worst part for me, but I can see that for a lot of people. The most I use FP in my day to day is React and Redux -- I don't use FP for work so this was just a quick side project!


I agree, just returning a value in a Maybe and then getting the value out of the Maybe functor by pattern matching via 'case' is clunky. That's not what Maybe is invented for.

The Maybe type can, in fact, reduce clunkiness of the code. But only if you are using it as (Applicative) Functor or Monad to propagate the failure transparently through some other part of your code.

As an example, in one of my projects, I have a function 'intersection' that computes a point of intersection for two given line segments. Two line segments can have an intersection, but need not to have. So using Maybe seems good.

intersection :: LineSeg -> LineSeg -> Maybe Point

In the further code, there is a function 'triangle' that takes three Points and returns the corresponding Triangle:

triangle :: Point -> Point -> Point -> Triangle

As you can guess, the program will at some point compute the Triangle built by three line segments. And this is where Maybe begins to shine:

triangleABC = triangle <$> intersection a b <*> intersection a c <*> intersection b c

You see what happend here: The triangle function was written for Points that really exist. But I have applied it to intersection points that maybe exist but maybe not! I could do so, because I used Maybe as Applicative Functor.

Of course, if any of the three intersections doesn't exist, triangleABC is Nothing. If they all three exist, triangle ABC is in a Just. Maybe reduces the need for clunky case analysis, but only if you really use it as Applicative Functor or Monad, that helps you to propagate Maybe data through your code. Otherwise it makes the code clunky, yes.

You can build bigger structures of 'Maybe Triangle's. The point is: You can write your code without having to think about (and deal with) the annyoing failures, you can concentrate on the cases where all is good, like I have done with my function 'triangle'.

I wanted to share some real code examples regarding Maybe, but it is better explained in full length here: learnyouahaskell.com/functors-appl... and here: learnyouahaskell.com/a-fistful-of-...

Edit: <$> seems to be <~ in Elm and <*> is ~
See the example in elm-lang.org/blog/announce/0.7


I'm always puzzled why languages emerge and evolve, so far the only explanation is the Babel story in the Bible, it's meant to stop people from communicating because they try to build towers. Elm is a definitively maybe, sounds like it's going to rot.


This is great! I've been meaning to try out Elm for a while since I took a tiny workshop on it at a conference - I'm interested to see if I run into the same feels/issues/other things that you did!

Thanks Ali! 💯💯💯


I am very curious to know why that company asked you to do work specifically in Elm. Would you please share that, and what framework you ended up developing with instead of Elm for that project?

As a student I found FP interesting as a computer science concept, but I had never imagined why anyone would use any (pure) FP language for a commercial purpose.


Sounds like a lot of your issues may be around FP concepts in general?

For instance, do you dislike Haskell? Would Idris drive you crazy?


Ali. Keep trying it again! I've kept coming back to it because of my conviction that Functional Programming skills will improve my programming whatever language I develop in.


I've been doing a bunch of FP in JavaScript recently, and I love it there! Just don't think I love a fully functional language (or the syntax of it!)


The syntax or the concepts?
I feel like a lot of it just extends from lambda calc. There are definitely differences syntactically amongst for langs....just look at erlang and compare it to elm.


Keep trying to learn new things! Good on ya 😀


I try to learn Elm too in the past. Look like after a year, I didn't manage to proceed into part 2 - k4ml.me/learning-elm-part-1/.