Functions in Unison are applied using a space, like f x y
. Operators are applied using infix notation, like x + y
. The order in which functions and operators are applied is determined by their syntactic precedence.
Any function with an unqualified name that consists of only operator characters is an operator. For example, +
, *
, ==
, &&
, and ||
are all operators, as are Nat.+
, Int.*
, Float.==
, etc.
Technically speaking &&
and ||
are not functions but reserved keywords, but they are treated syntactically as if they were operators.
Operator precedence
The Unison language has a fixed precedence for operators determined by the operator's name. A higher precedence means that the operator binds more tightly. For example, *
has higher precedence than +
, so 1 + 2 * 3
is parsed as 1 + (2 * 3)
. Operators with higher precedence are applied first.
Operator | Precedence |
^ , ^^ , and ** | 6 |
* , / , and % | 5 |
+ and - | 4 |
< , > , >= , and <= | 3 |
== , === , != , and !== | 2 |
&& and & | 1 |
|| and | | 0 |
Any other combination of "!$%^&*-=+<>~\\/|:" | No precedence |
When two operators with the same precedence are used in the same expression, the associativity of the operator determines the order in which the operators are applied. Currently all operators associate to the left. For example, 1 + 2 - 3
is parsed as (1 + 2) - 3
and 1 - 2 + 3
is parsed as (1 - 2) + 3
.
When an operator with no precedence rule is used in an expression with operators that do have a precedence rule, the operator with no precedence always just associates to the left. For example, 1 + 2 * 3 $ 4 + 5
is parsed as ((1 + (2 * 3)) $ 4) + 5
. Another way to think of this is that the operator with no precedence rule has lower precedence than any operator to its left and higher precedence than any operator to its right. You are encouraged to split such expressions into smaller parts to aid readability, but this rarely comes up in practice.
When your code is printed back to you by Unison, it will be displayed with minimal necessary parentheses. If Unison's precedence rules change, old definitions will get displayed with the parentheses needed for the new precedence rules.
Function application
Function application binds more tightly than any operator. So f x + g y
is the same as (f x) + (g y)
. Function application associates to the left, so f x y z
is the same as ((f x) y) z
.
Function application binds less tightly than keywords that introduce blocks. So f let x
is the same as f (let x)
and f if b then p else q
is the same as f (if b then p else q)
.
Function application binds less tightly than !
and '
(see delayed computations), so !f x y
is the same as f () x y
and 'f x y
is the same as (_ -> f) x y
.