Operators for function application

When working with Unison code, you might encounter the followingoperatorswhich are provided by thebaselibrary. They are commonly used for manipulating the order in which a function is applied to its arguments.

a<<b

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

<<,also known as "compose," takes in two functionsb -> canda -> band returns a function froma -> c.

composeEx : Nat -> Boolean
composeEx = Boolean.not << Nat.isEven

Piping multiple functions together with the compose operator looks like:

composeMultiEx : Text -> Boolean
composeMultiEx = Boolean.not << Nat.isEven << Text.size

The expression is actually parsed:

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

Giving us a function that expectsText.size'sargument ofTextand returning the final result of applying theBoolean.notfunction.

📌
Operators and infix function application are grouped with the leftmost expressions happening first. In other words they areleft-associative.Read more about this in the language guide section aboutoperators and function application

a>>b

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

>>,also known asandThen,is likecomposewith the function argument order reversed. It takes in two functionsa->bandb->cand returns a function froma->c.

andThenEx : Boolean
andThenEx = ((>>) Nat.isEven Boolean.not 4)

Piping together multiple>>calls looks like:

andThenMultiEx : Boolean
andThenMultiEx = ((>>) (Text.size >> Nat.isEven) Boolean.not "Boo")

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. When using|>it's helpful to remember that the function argument should be on theleft handside of the operator. 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.

pipeRightEx : Optional Nat
pipeRightEx =
  use Nat +
  Some 5 |> Optional.filter Nat.isEven |> Optional.map (n -> n + 1)

You might find that there's a greater fit between the semantic order of this expression and the order in which the function calls are applied than in the non|>version of this expression:

🧠

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

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

If the operator is thelastthing on the line, the following expression does not need to be indented.

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.