In which I get angry because some aspect of Elm seems... well, weird to me, and the docs aren't helping, so I jot down these notes in order to force myself to better grasp the topic, because writing forces me to think deeply about things in a way that I'm incapable of doing otherwise gaaasspp
Background: In Elm, functions are pure. Given the same input, they'll always return the same output. That isn't the case in JavaScript, where for example a function can return different values on successive calls, like Math.random()
or Date.now()
.
Thus, a function that takes zero args is conceptually no different than a variable. A variable holds a value. A zero-arg function only returns one possible value. This is reflected in Elm syntax. Look at how you annotate and declare a variable in Elm:
foo : Int
foo = 5
Then look at how you annotate and declare functions:
addOne : Int -> Int
foo x = x + 1
add : Int -> Int -> Int
foo x y = x + y
Notice the pattern? A two-arg function has two ->
s on it. An one-arg has one, and a zero-arg has zero. There's literally no other difference. It's as if there were no variables in Elm, just functions with zero or more args.
Any function that takes N args, where N > 1, is also a function that takes fewer-than N args, and which returns a new function expecting the remaining args. Suppose we have a list of ints, and want a new list in which we've added 2
to every item. Obviously, we'll need a function to pass to List.map
:
add2 : Int -> Int
add2 a = a + 2
myList : List Int
myList = [1, 2, 3];
otherList : List Int
otherList = List.map add2 myList
But suppose we already have a function which accepts two ints and adds them together:
add : Int -> Int -> Int
add a b = a + b
We can partially apply the add
function in order to get our add2
function.
myList : List Int
myList = [1, 2, 3];
otherList : List Int
otherList = List.map (add 2) myList
Also notice that partial application only happens left-to-right. To partially-apply in the middle of the arg list, you have to write a custom function.