Skip to content

Pattern Matching

Match expressions, destructuring, and exhaustive patterns.


Pattern matching is the primary control flow in Qosm. There's no if/else — use match instead.

Basic syntax

match expr with (
| pattern1 -> result1
| pattern2 -> result2
| _ -> default_result)

Branches are parenthesized and separated by |.

Variable patterns

Variables bind the matched value:

match 42 with (
| x -> x + 1)
// 43

Wildcard

_ matches anything without binding:

match some_value with (
| _ -> "matched anything")

Scalar patterns

Match exact values:

match n with (
| 0 -> "zero"
| 1 -> "one"
| _ -> "many")

Boolean matching (instead of if/else)

let abs x =
  match x >= 0 with (
  | true -> x
  | false -> 0 - x);

let max a b =
  match a > b with (
  | true -> a
  | false -> b);

Variant patterns

Nullary variants

match color with (
| Red -> "#ff0000"
| Green -> "#00ff00"
| Blue -> "#0000ff")

Named field destructuring

match result with (
| Ok{value: v} -> "Success: " ++ to_string v
| Err{value: e} -> "Error: " ++ .message e)

Positional destructuring (single-field variants)

match opt with (
| Some n -> n + 1
| None -> 0)

Record patterns

Destructure record fields:

match person with (
| {name: n, age: a} -> n ++ " is " ++ to_string a)

Array patterns

match arr with (
| [] -> "empty"
| [x] -> "one element: " ++ to_string x
| [x, y] -> "two elements"
| [x, ...rest] -> "head: " ++ to_string x)

The [x, ...rest] pattern binds the first element to x and the remaining array to rest.

[x, ...rest] is pattern-only. To build arrays, use append [x] rest, not [x, ...rest].

Nested patterns

Patterns can be nested:

match result with (
| Ok{value: {name: n}} -> "Name: " ++ n
| Err{value: ParseError{message: m}} -> "Parse error: " ++ m
| Err{value: _} -> "Other error")

Common Result/Option patterns

// Option from head/nth
let first_or_zero arr =
  match head arr with (
  | Some{value: x} -> x
  | None -> 0);

// Result from capability calls
let safe_fetch url =
  match http_get {url: url, headers: []} with (
  | Ok{value: body} -> body
  | Err{value: e} -> "Error: " ++ .message e);

// Chaining Results with and_then
let pipeline input =
  http_get {url: input, headers: []}
  |> and_then (λ body -> parse_json @{name: String} body);