Curried Form In Elm Functions

Here’s a newbie Elm thing that made me stop and think:

In the docs, there’s a Contracts section, where type annotations are discussed. Some examples like this one are eventually given:

longestName : List String -> Int
longestName names =
  List.maximum (List.map String.length names)

That first line annotates the following function, longestName, as a function that takes a List of Strings and returns an Int. Pretty straightforward.

Later, when I started looking at the Elm Architecture tutorial, I came across a function with a type annotation that looked like this:

update : Action -> Model -> Model
update action model =
  case action of
    Increment ->
      model + 1

    Decrement ->
      model - 1

My brain wasn’t quite ready for Action -> Model -> Model. The function has two parameters. So why doesn’t the annotation?

Here’s how to think about it: It’s a function that takes an Action and returns a function. The function it returns takes a Model and returns a Model.

Curried Form

Elm functions are defined in “curried form”. That’s what Action -> Model -> Model is. A function in curried form is expressed as a chain of smaller functions, each of which takes a single argument and returns a function. (Until the last one, which returns the ultimate result.)

Maybe it’s helpful to imagine parentheses here: Action -> (Model -> Model). Better?

By contrast, a seasoned C#/Javascript developer like me is used to something more like (Action, Model) -> Model. Two parameters, one result.

(“Currying”, by the way, is the process of taking a function with multiple parameters – the kind I’m used to – and transforming it into the chain-of-single-parameter-functions form that Elm uses by default.)

Partial Application

If I call the update function but provide only the first argument, Elm returns a new function. E.g., at the REPL:

> update Increment
<function>: Model -> Model

What does this new function do? It does what the update function does, without requiring (or allowing) me to pass in an Action. The Action is already known. So this function always takes a Model and returns a new Model with a value of the argument Model’s value plus one. It always increments.

This is called “partial application”. Because I’ve applied only part of the function, bound only one of the parameters. The result is a new function I can use to send in the rest.

(Note: Curried form makes partial application easy. But partial application does not require curried form.)