Pattern Matching
Pattern matching with match is the primary way to inspect and destructure values in Almide. Every match must be exhaustive — the compiler verifies that all possible cases are covered.
Basic match
Section titled “Basic match”match direction { North => "up", South => "down", East => "right", West => "left",}match is an expression: it returns a value. All arms must produce the same type.
Arms are separated by commas. Each arm has the form Pattern => expr.
Pattern types
Section titled “Pattern types”Wildcard
Section titled “Wildcard”_ matches any value without binding it:
match status { 200 => "ok", 404 => "not found", _ => "other",}Identifier (binding)
Section titled “Identifier (binding)”A bare name binds the matched value to a variable:
match list.first(items) { some(x) => println("first: ${x}"), none => println("empty"),}Literal
Section titled “Literal”Match against specific values:
match command { "start" => run(), "stop" => halt(), "status" => report(), _ => err("unknown command"),}Supports Int, Float, String, and Bool literals. Negative literals are supported:
match n { 0 => "zero", 1 => "one", -1 => "negative one", _ => "other",}Option patterns
Section titled “Option patterns”some(pattern) and none destructure Option[T]:
match map.get(config, "port") { some(port) => println("port: ${port}"), none => println("using default port"),}Result patterns
Section titled “Result patterns”ok(pattern) and err(pattern) destructure Result[T, E]:
match int.parse(input) { ok(n) => n * 2, err(e) => { println("parse error: ${e}") 0 },}Constructor patterns
Section titled “Constructor patterns”Destructure variant type cases:
type Shape = | Circle(Float) | Rect{ width: Float, height: Float } | Point
fn describe(s: Shape) -> String = match s { Circle(r) => "circle with radius ${float.to_string(r)}", Rect{ width, height } => "${float.to_string(width)}x${float.to_string(height)}", Point => "point", }Unit constructors match without parentheses. Tuple constructors use CaseName(patterns...). Record constructors use CaseName{ fields... }.
Record patterns
Section titled “Record patterns”Destructure record variant cases with field names:
match shape { Rect{ width, height } => width * height, Rect{ width, .. } => width, // .. ignores remaining fields _ => 0.0,}The .. syntax allows partial matching, ignoring fields you don’t need.
Tuple patterns
Section titled “Tuple patterns”Destructure tuples directly:
match point { (0, 0) => "origin", (x, 0) => "on x-axis", (0, y) => "on y-axis", (x, y) => "at (${int.to_string(x)}, ${int.to_string(y)})",}Guards
Section titled “Guards”Add if condition after a pattern for additional constraints:
match n { x if x > 0 => "positive", x if x < 0 => "negative", _ => "zero",}When a guard is false, the next arm is tried:
fn classify(score: Int) -> String = match score { n if n >= 90 => "A", n if n >= 80 => "B", n if n >= 70 => "C", _ => "F", }Guards can use any boolean expression:
match item { some(s) if string.len(s) > 0 => process(s), some(_) => err("empty string"), none => err("missing"),}Exhaustiveness
Section titled “Exhaustiveness”The compiler ensures every possible value is covered. Missing cases are compile errors:
type Color = Red | Green | Blue
match color { Red => "red", Green => "green", // Compile error: non-exhaustive match, missing: Blue}Use _ as a catch-all when you don’t need to handle every case individually:
match color { Red => "red", _ => "not red",}Pipe into match
Section titled “Pipe into match”The pipe operator can feed a value directly into match:
list.get(args, 1) |> match { some(cmd) => cmd, none => "help",}Nested patterns
Section titled “Nested patterns”Patterns can be nested to match complex structures:
match result { ok(some(value)) => use(value), ok(none) => default(), err(e) => handle(e),}Next steps
Section titled “Next steps”- Types & Values — variant types and records
- Error Handling — matching on Result and Option
- Control Flow — if-then-else and guard