Elm Christmas

Operators are functions, too

A 2 minute read written by
Robin Heggelund Hansen
12.12.2020

Previous postNext post

Much of Elm's power stems from the fact that most things are just functions. So how do operators fit in?

Imagine that we have a list of first names (like Stanly, Paul and so forth), and another list of last names (Henderson, Hansen, Copperfield etc.). Also imagine that we have been given a task to come up with a set of full names, to be used as an example for a form we're making. We could solve the problem like so:

exampleNames : List String
exampleNames =
    List.map2 (\firstName lastName -> firstName ++ lastName) listOfFirstNames listOfLastNames

This works, but the anonymous function we've made takes up a surprisingly large amount of screen real estate considering how little it actually does.

We could try to improve the situation by turning this into a proper function:

combineStrings : String -> String -> String
combineStrings left right =
    left ++ right
    
exampleNames : List String
exampleNames =
    List.map2 combineStrings listOfFirstNames listOfLastNames

This works, but creating a function which just applies the ++ operator feels like more work than should be necessary.

The good news is that it is, in fact, uneccessary. Operators are functions, too.

Operators are special as they're the only functions which can be used with infix notation. That means its arguments are placed on both sides of the function. However, you can turn an operator back into a "regular" function by wrapping it with parenthesees, like this:

combineStrings : String -> String -> String
combineStrings left right =
    (++) left right

As long as they're wrapped by parenthesees, operators work like any other function in Elm. Which means we could write the original exampleNames implementation like so:

exampleNames : List String
exampleNames =
    List.map2 (++) listOfFirstNames listOfLastNames

You might have noticed that we have a bug here. Normally, a full name will have its first and last name seperated by whitespace, but our current implementation will join the first and last name without any space between them.

We could solve this by prefixing all last names with a single space, and then combine first names and last names together. Since operators are just functions, this allows us to make use of partial application:

exampleNames : List String
exampleNames =
  List.map ((++) " ") listOfLastNames
      |> List.map2 (++) listOfFirstNames

Summary

While operators work differently from regular functions by default, you can make them work like any regular function by wrapping them in parentheses. Done correctly, this can make your code more succinct and easier to read.

Read the next post
Bekk