Patterns
A pattern simultaneously describes value and shape. Patterns can include,
for example, x
, True
, [1, 2, 3]
, and ("hello", x)
. These patterns
can be broken down:
- The pattern
x
matches anything. - The pattern
True
matches the shapeBool
with the valueTrue
. - The pattern
[1, 2, 3]
matches the shapeList Int
of[_, _, _]
with respective values1
,2
, and3
. - The pattern
("hello", x)
matches the shape(String, _)
where the first value is"hello"
and the second is any value.
Patterns can be used in several locations.
- Let statements (must be irrefutable).
let x = 5
let (message, number) = ("hello", 22) - Match expressions.
let value = match Some(1001) {
Some(x) => x
None => 0
} - Function arguments (must be irrefutable).
def sum_pairs((a, b): (Int, Int), (x, y): (Int, Int)) -> (Int, Int) {
(a + x, b + y)
}
assert_eq(sum_pairs((10, 20), (3, 4)), (13, 24))
A pattern in a let binding must be irrefutable, meaning that it always
matches. If the pattern can fail (e.g., matching on an Option
), it
cannot be used in a let binding.
When a match expression is used, it must be exhaustive over the list of potential matches, meaning that every possible value of the match argument must match with at least one of the patterns and guards.
Values in patterns
Patterns can include value literals.
match (3, 1) {
(3, _) => "first is 3"
(2, 2) => "both are 2"
_ => "something else"
}
Destructuring patterns
Destructuring unpacks a composite value into its parts. This applies to tuple-like types, record-like types, and list types. Tuple-like values are simply destructured by position.
let (name, message) = ("Viviette", "Hello!")
Record-like types can use ..
to omit fields and :
to rename others. Field
labels can appear in any order; however, the ..
must appear last.
type Person(name: String, age: Int)
let Person(age: years, ..) = Person(name: "Viviette", age: 27)
assert_eq(years, 27)
// Uncommenting the following line results in a compile-time
// error as age is not defined, only years.
// assert_eq(age, "Viviette")
Lists can be destructured using ..
, which can appear at most once in a list
pattern.
// Capture the tail.
let [a, b, ..c] = [1, 2, 3, 4, 5]
assert_eq((a, b, c), (1, 2, [3, 4, 5]))
// Capture at an arbitrary position in the list.
let [x, ..y, z] = [1, 2, 3, 4, 5]
assert_eq((x, y, z), (1, [2, 3, 4], 5))
// It can also be empty.
let [p, ..q, r] = [1, 2]
assert_eq((p, q, r), (1, [], 2))
// The name can also be omitted.
let [u, .., v] = [1, 2, 3, 4, 5]
assert_eq((u, v), (1, 5))
Outer match patterns
An outer match uses @
to match an entire value and its structure.
type Person(name: String, age: Int)
let person @ Person(name, ..) = Person(name: "Viviette", age: 27)
// Both the `person` and `name` are bound to values.
assert_eq(person, Person(name: "Viviette", age: 27))
assert_eq(name, "Viviette")