Pattern Matching
Pattern matching is used to branch on a pattern or destructure data.
Many expressions have a set of pattern_matching_clause
rules used for
branching.
Branching
Syntax
Show source
pattern_matching_clause
= clause_patterns clause_guard? "->" clause_body
Show source
clause_patterns
= "(" (pattern ("," pattern)* ","? )? ")"
Show source
clause_guard
= "when" expression
Show source
clause_body
= expression
/ ("{" (expression ";")+ "}")
Example
let natural: class[int] {
(n) -> n >= 0,
};
let collatz: func[(natural) -> natural] {
(n) when n % 2 = 0 -> n / 2,
(n) -> 3 * n + 1,
};
Semantics
In a class constraint, if no clause matches, then the object MUST NOT belong to the class:
let natural: class[int] {
(n) when n >= 0 -> true,
};
# is equivalent to:
let natural: class[int] {
(n) when n >= 0 -> true,
(_) -> false,
};
In all other cases, if no clause matches, an exception MUST be thrown, the value of this exception is defined by the implementation:
let foo: func[(int) -> @ok] {
(1) -> @ok,
(2) -> @ok,
};
# is equivalent to:
let foo: func[(int) -> @ok] {
(1) -> @ok,
(2) -> @ok,
(_) -> throw @implementation_defined_error,
};
Each clause MUST create a new scope.
A clause MUST evaluate to the value the last expression in its branch evaluates to.
The guard expression of a clause MUST evaluate to a boolean (true
or false
).
If an exception is thrown in a guard expression, it SHOULD be ignored and be
equivalent to returning false
.
Pattern syntax
Show source
pattern
= pattern_ignore
/ pattern_binding
/ pattern_literal
/ pattern_tuple
/ pattern_namedtuple
/ pattern_list
/ pattern_list_headtail
/ pattern_eval
Show source
pattern_ignore
= "_"
Show source
pattern_binding
= identifier
Show source
pattern_literal
= atom / bool / number / string
Show source
pattern_tuple
= ("(" ("..." ","?)? ")")
/ ("(" pattern ("," pattern)* ("," "...")? ","? ")")
Show source
pattern_namedtuple
= ("{" ("..." ","?)? "}")
/ ("{" pattern_namedtuple_pair ("," pattern_namedtuple_pair)* ("," "...")? ","? "}")
Show source
pattern_namedtuple_pair
= identifier ":" pattern
Show source
pattern_list
= ("[" ("..." ","?)? "]")
/ ("[" pattern ("," pattern)* ("," "...")? ","? "]")
Show source
pattern_list_headtail
= "[" pattern ("," pattern)* ","? "|" pattern "]"
Show source
pattern_eval
= "${" expression "}"
Semantics
The ellipsis ...
means "and the rest":
# a = 1, b = 2
[a, b, ...] := [1, 2, 3, 4];
# a = 1, b = 2, tail = [3, 4]
[a, b | tail] := [1, 2, 3, 4];
# this will throw an error
[a, b] := [1, 2, 3, 4];
Binding a value to a name MUST happen immediatly:
# a = 2, because it is rebound a second time
(a, a) := (1, 2);
# a = 1 and can be used immediatly in an `pattern_eval` rule
(a, ${a + 1}) := (1, 2);
# will throw an error, because a = 1, and 1 does not match 2
(a, ${a}) := (1, 2);