Amatch expressionhas the general form:
match e with
pattern_1 -> block_1
pattern_2 -> block_2
…
pattern_n -> block_n
Wheree
is an expression, called thescrutineeof the match expression, and eachcasehas apattern to match against the value of the scrutineeand ablockto evaluate in case it matches.
The evaluation semantics of match expressions are as follows:
- The scrutinee is evaluated.
- The first pattern is evaluated and matched against the value of the scrutinee.
- If the pattern matches, any variables in the pattern are substituted into the block to the right of its
->
(called thematch body)and the block is evaluated. If the pattern doesn’t match then the next pattern is tried and so on.
It's possible for Unison to actually evaluate cases in a different order, but such evaluation should always have the same observable behavior as trying the patterns in sequence.
It is an error if none of the patterns match. In this version of Unison, the error occurs at runtime. In a future version, this should be a compile-time error.
Unison provides syntactic sugar for match expressions in which the scrutinee is the sole argument of a lambda expression:
cases
pattern_1 -> block_1
pattern_2 -> block_1
…
pattern_n -> block_n
-- equivalent to
e -> match e with
pattern_1 -> block_1
pattern_2 -> block_1
…
pattern_n -> block_n
Apatternhas one of the following forms:
Blank patterns
Ablank patternhas the form_
.It matches any expression without creating a variable binding.
For example:
_ = 42
"Always matches"⧨"Always matches"
Literal patterns
Aliteral patternis a literalBoolean
,Nat
,Int
,Char
,orText
.A literal pattern matches if the scrutinee has that exact value.
For example:
match 2 Nat.+ 2 with
4 -> "Matches"
_ -> "Doesn't match"⧨"Matches"
Variable patterns
Avariable patternis aregular identifierand matches any expression. The expression that it matches will be bound to that identifier as a variable in the match body.
For example:
match 1 + 1 with
x -> x + 1
As-patterns
Anas-patternhas the formv@p
wherev
is aregular identifierandp
is a pattern. This pattern matches ifp
matches, and the variablev
will be bound in the body to the value matchingp
.
For example, this expression evaluates to3
:
Constructor patterns
Aconstructor patternhas the form `C p1 p2 … pn'' whereC
is the name of a data constructor in scope, andp1
throughpn
are patterns such thatn
is thearityofC
.Note thatn
may be zero. This pattern matches if the scrutinee reduces to a fully applied invocation of the data constructorC
and the patternsp1
throughpn
match the arguments to the constructor.
For example, this expression usesSome
andNone
,the constructors of theOptional
type, to return the 3rd element of the listxs
if present or0
if there was no 3rd element.
List patterns
Alist patternmatches aList t
for some typet
and has one of three forms:
head List.+: tail
matches a list with at least one element. The patternhead
is matched against the first element of the list andtail
is matched against the suffix of the list with the first element removed.init :+ last
matches a list with at least one element. The patterninit
is matched against the prefix of the list with the last element removed, andlast
is matched against the last element of the list.- Aliteral list patternhas the form
[p1, p2, … pn]
wherep1
throughpn
are patterns. The patternsp1
throughpn
are matched against the elements of the list. This pattern only matches if the length of the scrutinee is the same as the number of elements in the pattern. The pattern[]
matches the empty list. part1 List.++ part2
matches a list which composed of the concatenation ofpart1
andpart2
.At least one ofpart1
orpart2
must be a pattern with a known list length, otherwise it's unclear where the list is being split. For instance,[x, y] List.++ rest
is okay as isstart List.++ [x, y]
,but justa ++ b
is not allowed.
Examples:
first : [a] -> Optional a
first = cases
h +: _ -> Some h
[] -> None
last : [a] -> Optional a
last = cases
_ :+ l -> Some l
[] -> None
exactlyOne : [a] -> Boolean
exactlyOne = cases
[_] -> true
_ -> false
lastTwo : [a] -> Optional (a, a)
lastTwo = cases
start ++ [a, a2] -> Some (a, a2)
_ -> None
firstTwo : [a] -> Optional (a, a)
firstTwo = cases
[a, a2] ++ rest -> Some (a, a2)
_ -> None
Tuple patterns
Atuple patternhas the form(p1, p2, … pn)
wherep1
throughpn
are patterns. The pattern matches if the scrutinee is a tuple of the samearityas the pattern andp1
throughpn
match against the elements of the tuple. The pattern(p)
is the same as the patternp
,and the pattern()
matches the literal value()
of the trivial type {()} (both pronounced “unit”).
For example, this expression evaluates to `4`:
Ability patterns (orRequest
patterns)
Anability patternonly appears in anability handlerand has one of two forms (seeAbilities and ability handlersfor details):
{C p1 p2 … pn -> k}
whereC
is the name of an ability constructor in scope, andp1
throughpn
are patterns such thatn
is the arity ofC
.Note thatn
may be zero. This pattern matches if the scrutinee reduces to a fully applied invocation of the ability constructorC
and the patternsp1
throughpn
match the arguments to the constructor. The scrutinee must be of typeRequest A T
for some ability{A}
and typeT
.The variablek
will be bound to the continuation of the program. If the scrutinee has typeRequest A T
andC
has typeX ->{A} Y
,thenk
has typeY -> {A} T
.{p}
wherep
is a pattern. This matches the case where the computation ispure(the value of typeRequest A T
calls none of the constructors of the ability{A}
).A pattern match on aRequest
is not complete unless this case is handled.
See the section onabilities and ability handlersfor examples of ability patterns.
Guard patterns
Aguard patternhas the formp | g
wherep
is a pattern andg
is a Boolean expression that may reference any variables bound inp
.The pattern matches ifp
matches andg
evaluates totrue
.
For example, the following expression evaluates to6
:
match 1 + 2 with
x
| x == 4 -> 0
| x + 1 == 4 -> 6
_ -> 42