⛅ Coming soon: create Unison Cloud clusters in minutes on your own infrastructure. Learn more

Operators for function application

The following operators are provided by the @unison/base library. They are commonly used for changing how a function is applied.

b << a

<< : (b ->{𝕖} c) -> (a ->{𝕖} b) -> a ->{𝕖} c

<<, also known as "compose," takes in two functions, b -> c and a -> b, and returns a function of type a -> c.

natToText : Nat -> Text natToText = Boolean.toText << Nat.isEven natToText 24
"true"

Piping multiple functions together with the compose operator looks like:

textToBool : Text -> Boolean textToBool = Boolean.not << Nat.isEven << Text.size textToBool "hello"
true

The expression is actually parsed:

((Boolean.not << Nat.isEven) << Text.size)

Which gives us a function that expects Text.size's argument of Text and returns a Boolean

📌
Repeated infix operator application is generally grouped with the leftmost expressions happening first. In other words, they are left-associative. Read more about this in the language guide section about operators and function application

a >> b

>> : (a ->{𝕖} b) -> (b ->{𝕖} c) -> a ->{𝕖} c

>>, also known as andThen, is like compose with the function argument order reversed. It takes in two functions a -> b and b -> c and returns a function from a -> c.

Nat.isEven >> Boolean.not

Piping together multiple >> calls looks like:

Text.size >> Nat.isEven >> Boolean.not

a |> b

|> : a -> (a ->{𝕖} b) ->{𝕖} b

While >> returns a function, |> allows us to apply an argument to a function, returning the value of that function call. The value of this operator might not be immediately obvious—after all, why use special operators for function application when parentheses will suffice 🤔—but you'll often see multiple instances of the |> operator chained together to form a complete expression.

This version reads in the same order that things happen: start with Some 2, filter it, then map over the result. Compare that to the version without |>:

Here, the order in which the functions are applied is the same, but it may be harder to read: you start inside the parens and work out instead of left-to-right.

🧠

When chaining the |> operator in a multi-line expression, the operator should be the first thing on a new line and indented.

List.range 0 10
   |> map (pow 2)
   |> sum

a <| b

<| : (a ->{𝕖} b) -> a ->{𝕖} b

When using <|, the function should be on the left hand side of the operator with the function's argument on the right hand side. You can read the <| operator as "pipe backwards." You might choose to use this operator when the argument to the function in question needs some "pre-processing" which would otherwise involve parentheses.

Note that the <| operator does not change the precedence of the operator function calls. The leftmost sub-expression is still executed first. You can use parentheses to change the grouping.