Pattern Matching
Pattern matching lets you destructure and inspect values.
Pattern Types
Literal Patterns
Match exact values:
match n
0 -> "zero"
1 -> "one"
2 -> "two"
_ -> "many"
endWorks with: Int, Float, Bool, String
Wildcard Pattern
Match anything:
match x
0 -> "zero"
_ -> "not zero"
endBinding Patterns
Capture matched value:
match n
0 -> "zero"
x -> "got {x}"
endTuple Patterns
match point
(0, 0) -> "origin"
(x, 0) -> "on x-axis"
(0, y) -> "on y-axis"
(x, y) -> "({x}, {y})"
endList Patterns
match items
[] -> "empty"
[x] -> "one: {x}"
[x, y] -> "two: {x}, {y}"
[first, ...rest] -> "first: {first}, rest: {length(rest)}"
endWith rest capture:
match items
[first, second, ...rest] -> # first two elements, rest in list
[...rest, last] -> # all but last in rest, last separately
endRecord Patterns
match user
User(name: "Admin", ..) -> "administrator"
User(name: n, active: true, ..) -> "active: {n}"
User(active: false, ..) -> "inactive"
endEnum Patterns
Simple enum:
match status
Pending -> "waiting"
Active -> "running"
Done -> "complete"
endWith data:
match result
Ok(value) -> "success: {value}"
Err(msg) -> "error: {msg}"
endType Patterns
Check type in unions:
match value
n: Int -> "int: {n}"
s: String -> "string: {s}"
b: Bool -> "bool: {b}"
endGuard Patterns
Add conditions:
match n
x if x < 0 -> "negative"
x if x == 0 -> "zero"
x if x < 10 -> "small positive"
_ -> "large positive"
endOr Patterns
Match multiple patterns:
match c
"a" | "e" | "i" | "o" | "u" -> "vowel"
_ -> "consonant"
endNested Patterns
match result
Some(Ok(value)) -> "success: {value}"
Some(Err(msg)) -> "failed: {msg}"
None -> "nothing"
endMatch Expression
Match returns a value:
let label = match status
Pending -> "pending"
Active -> "active"
Done -> "done"
endEach arm must return the same type.
Match Statement
Match can be used as a statement:
match status
Pending -> print("still waiting")
Active -> print("now active")
Done -> print("completed")
endDestructuring in let
Patterns work in let bindings to extract values from structured data in a single declaration.
Tuple Destructuring
Bind each element of a tuple to a variable:
let (a, b) = (1, 2)
let (x, y, z) = get_coordinates()Nested tuple destructuring:
let (name, (lat, lon)) = ("Office", (37.7749, -122.4194))List Destructuring
Bind list elements, optionally capturing the rest:
let [first, ...rest] = [1, 2, 3, 4]
let [head, second, ...tail] = itemsRecord Destructuring
Extract fields from a record by name. Use field punning (shorthand) when the binding name matches the field name:
let Point(x:, y:) = origin # field punning: binds x and y
let Point(x: px, y: py) = point # rename: binds px and py
let User(name: n, ..) = user # partial: binds n, ignores other fieldsRecord destructuring with positional syntax:
let Point(x, y) = pointType Annotations
Destructured bindings can include type annotations:
let (a: Int, b: String) = (42, "hello")Destructuring in for
for (index, item) in enumerate(items)
print("{index}: {item}")
end
for [key, value] in pairs
print("{key} = {value}")
endPattern Matching Rules
- Patterns are tried in order — First match wins
- Matches must be exhaustive — Use
_for fallback - Guards are evaluated after match — Pattern must match first
- Bindings must be unique — Can't bind same name twice
Examples
HTTP Status
cell status_message(code: Int) -> String
match code
200 -> "OK"
201 -> "Created"
204 -> "No Content"
400 -> "Bad Request"
401 -> "Unauthorized"
403 -> "Forbidden"
404 -> "Not Found"
500 -> "Internal Server Error"
c if c >= 200 and c < 300 -> "Success"
c if c >= 400 and c < 500 -> "Client Error"
c if c >= 500 -> "Server Error"
_ -> "Unknown"
end
endJSON Navigation
cell get_string(json: Json, key: String) -> String | Null
match json
obj: map[String, Json] ->
match obj[key]
s: String -> s
_ -> null
end
_ -> null
end
endExpression Evaluator
enum Expr
Num(value: Float)
Add(left: Expr, right: Expr)
Sub(left: Expr, right: Expr)
Mul(left: Expr, right: Expr)
Div(left: Expr, right: Expr)
end
cell eval(expr: Expr) -> Float
match expr
Num(n) -> n
Add(l, r) -> eval(l) + eval(r)
Sub(l, r) -> eval(l) - eval(r)
Mul(l, r) -> eval(l) * eval(r)
Div(l, r) -> eval(l) / eval(r)
end
endBest Practices
- Order from specific to general — Put
_last - Use guards for complex conditions — Keep patterns simple
- Be exhaustive — Cover all cases or use
_ - Name bindings meaningfully —
xvsuser_id
Next Steps
- Declarations — Records, enums, cells
- Error Handling — Using result types