Elm baby steps: The language

Dec 4, 2022 · Functional programming, Elm, Currying · 4 minute read

Elm?

Elm is a functional programming language for creating web apps. As you will see in this blog post, programming in Elm is quite different from programming in JavaScript, but Elm does compile to JavaScript, which makes it work in every browser.

I am learning Elm because functional programming intrigues me, and building for the web as well, so it feels like the ideal language to try out.

You can do functional programming in JavaScript as well, but JS is not opinionated about what paradigm(s) you use, so there are always escape hatches from not programming fully functional. Which is not a bad thing at all of course, the fact you can use different paradigms in a language is ideal, because which paradigm is best? It depends of course.

So my reason I try out Elm is mainly because of curiosity. And because there are some very compelling language features that Elm offers: Static typing, immutability, pure functions, no side effects, no exceptions, no runtime errors, no null or undefined, etc. Sounds like a lot less to worry about.

Many reasons to try this out, let's go! This blog post will focus on the language itself.

Playground

Let's not install things, but just start coding by using the Elm playground: https://elm-lang.org/try

Here you can code with Elm, and see how it looks in the browser by clicking "Rebuild", which, like I said, compiles your Elm code to JavaScript, and shows the result in the browser right away.

Hello, World!

Let's create a variable with the name sayHello with the value "Hello, World!":

sayHello = "Hello, World!"

Let's output that value to the browser. Every Elm program needs a main function which is called by Elm. The main function expects an argument with the value that needs to be rendered, so let's try this:

sayHello = "Hello, World!"

main = sayHello

This does not work:

I cannot handle this type of `main` value:

3| main = sayHello
   ^^^^
The type of `main` value I am seeing is:

    String

The problem is that the type of main is a string, while it should be a function, so Elm can call it. So we need a function that returns our "Hello, World!" string. For this, we import the text function from Elm:

import Html exposing (text)

sayHello = "Hello, World!"

main = text sayHello

Here we import the 'text' function, and assign calling the text function with the sayHello argument to main, so Elm can call it and render "Hello, World!" in the browser.

Functions

Let's make a function that expects a name to say hello to:

sayHello name = "Hello, " ++ name

How to read this? sayHello is the name of the function, and it expects an argument called name. The = sign is for indicating where the function body starts, which here returns the string "Hello, ", followed by ++ which concatenates string, in this case the name argument.

With this, our program now looks like this:

import Html exposing (text)

sayHello name = "Hello, " ++ name

main = text (sayHello "Bouwe")

Note how main is still calling text, but the argument is the outcome of calling the sayHello function first. If I would not add the parentheses, I would be passing 2 arguments to text, while it only expects one.

Calculations and types

Let's do some calculations:

add a b = a + b

Here the add function expects two arguments, a and b, and it will return the total of these two numbers.

Numbers, you might think? How does Elm know these are numbers? Well, it's the + operator, which you can only use for numbers. Remember, we used the ++ operator in our previous example because we were dealing with strings. This shows how Elm is statically typed and will try to infer types. If it can not infer it, it will say so, and you can explicitly define the types if necessary.

Alright, let's write the outcome of the calculation to the screen:

import Html exposing (text)

add a b = a + b

main = text (add 1 1)

Here we pass the result of 1 + 1 to the text function by calling the add function. However, this does not work, because text expects a string while the result of add is a number. The compilation error says we probably want to use String.fromInt to convert it to a string first.

As with everything in Elm, String.fromInt is a function as well, so we could call it as follows:

main = text (String.fromInt (add 1 1))

This works, but I don't like all the parentheses, so let's break it up, and use a very cool language feature, the pipe operator:

total = add 1 1
        |> String.fromInt

main = text total

Here we call add, pass the value 1 twice, and the result from this, 2, is passed along to the next function in the pipeline, String.fromInt. This converts 2 to the string "2", and assigns it to the variable total, which is then passed to the text function for displaying.

Partial application

Elm supports partial application, in other words, calling a function with some of its arguments, which then returns a new function to which you only need to pass in the remaining arguments.

Let me show you some examples with the add function we just used:

result1 = add 10 20
-- result1 is the number 30

result2 = add 10
-- result2 is a function where the first argument (10) is already passed and applied,
-- and you only need to pass the second argument still

As the second call results in a function that adds 10 to any number argument passed to it, let's rename it to addTen, and call it:

addTen = add 10

result = addTen 20
-- result is the number 30

With this, we could create a bunch of functions, and reuse and compose them together however we need. I wrote a blog post about this already.

Conclusion

Cool, we covered a few basics about Elm, I learned a lot, and I hope you too! There is much more to discover of course, so stay tuned for another blog post. Topics I can think of are some more language syntax, but also how to render HTML, as Elm is for building web applications.

Thanks for reading!

Check out the code from this blog post here: https://github.com/bouwe77/elm-blog-posts/blob/main/Blog1.elm

Share on Twitter · Discuss on Twitter · Edit on GitHub