The following operators are provided by the @unison/base
library. They are commonly used for changing how a function is applied.
b <<
a
<<
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
a >>
b
>>
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
|>
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.
Some 2 |> Optional.filter Nat.isEven |> Optional.map (n -> n Nat.+ 1)⧨Some 3
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 |>
:
Optional.map (n -> n Nat.+ 1) (Optional.filter Nat.isEven (Some 2))⧨Some 3
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.
a <|
b
<|
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.