Match Expressions
match selects the first arm whose pattern matches the subject and evaluates its body.
Basic literal matching
Section titled “Basic literal matching”Match against numbers, strings, and booleans.
let label = match 42 { 1 => "one" 42 => "forty-two" _ => "other"};PRINT label; // "forty-two"
let lang = match "resonon" { "python" => "snake" "resonon" => "herb" _ => "unknown"};PRINT lang; // "herb"
let answer = match true { false => "nope" true => "yep"};PRINT answer; // "yep"Note matching
Section titled “Note matching”Note literals can be used as match patterns.
let root = C4;let name = match root { C4 => "C" D4 => "D" E4 => "E" _ => "other"};PRINT name; // "C"Note–number coercion
Section titled “Note–number coercion”Notes match against their MIDI number, and numbers match against notes. C4 is MIDI note 60, so C4 and 60 are interchangeable in match patterns.
// Note subject, number patternlet name = match C4 { 60 => "middle C" _ => "other"};PRINT name; // "middle C"
// Number subject, note patternlet name2 = match 60 { C4 => "middle C" D4 => "D" _ => "other"};PRINT name2; // "middle C"This is useful for dispatching on raw MIDI note numbers:
fn drum_name(note_num) { match note_num { C2 => "kick" Cs2 => "side stick" D2 => "snare" Fs2 => "hi-hat closed" As2 => "hi-hat open" _ => "other" }}PRINT drum_name(36); // "kick" (36 = C2)PRINT drum_name(38); // "snare" (38 = D2)NUL matching
Section titled “NUL matching”let val = NUL;let status = match val { NUL => "empty" _ => "has value"};PRINT status; // "empty"Non-NUL values do not match the NUL arm:
let status2 = match 42 { NUL => "empty" _ => "has value"};PRINT status2; // "has value"Wildcard catch-all
Section titled “Wildcard catch-all”_ matches anything. Place it last to handle all remaining cases.
let result = match 999 { 1 => "one" 2 => "two" _ => "unknown"};PRINT result; // "unknown"Variable binding
Section titled “Variable binding”A bare identifier captures the matched value into a variable available in the arm body.
let doubled = match 21 { n => n * 2};PRINT doubled; // 42Bindings can follow literal arms — the first match wins:
let desc = match 7 { 1 => "one" 2 => "two" x => x + 100};PRINT desc; // 107Guards
Section titled “Guards”Add if <condition> after a pattern to further constrain when an arm matches. The bound variable is available in the guard expression.
let size = match 15 { n if n > 100 => "huge" n if n > 10 => "big" n if n > 5 => "medium" _ => "small"};PRINT size; // "big"A guard that evaluates to false causes the arm to be skipped, and matching continues with the next arm:
let size2 = match 3 { n if n > 10 => "big" _ => "small"};PRINT size2; // "small"Wildcard with guard
Section titled “Wildcard with guard”The wildcard _ doesn’t bind a variable, but guards on wildcard arms can reference variables from the surrounding scope.
let threshold = 50;let level = match 42 { _ if threshold > 100 => "high threshold" _ if threshold > 25 => "medium threshold" _ => "low threshold"};PRINT level; // "medium threshold"Musical example: note range routing
Section titled “Musical example: note range routing”fn register(note) { match note { n if n < C3 => "bass" n if n < C5 => "mid" n if n < C7 => "treble" _ => "ultra-high" }}
PRINT register(A1); // "bass"PRINT register(E4); // "mid"PRINT register(C6); // "treble"Block bodies
Section titled “Block bodies”Use { ... } for multi-statement arm bodies. The last expression in the block is the arm’s value.
let computed = match "calc" { "calc" => { let a = 10; let b = 20; a + b } _ => 0};PRINT computed; // 30Match as expression
Section titled “Match as expression”match can appear anywhere an expression is expected, including let bindings.
let grade = match 92 { n if n >= 90 => "A" n if n >= 80 => "B" n if n >= 70 => "C" _ => "F"};
// Match with a computed subjectlet parity = match 2 + 3 { n if n % 2 == 0 => "even" _ => "odd"};PRINT parity; // "odd"Match as statement
Section titled “Match as statement”match can also stand alone as a statement.
let out = "";match 42 { 42 => { out = "matched 42"; } _ => { out = "no match"; }}PRINT out; // "matched 42"Exhaustiveness
Section titled “Exhaustiveness”Resonon does not check exhaustiveness at compile time. If no arm matches at runtime, a runtime error is raised.
// Runtime error: "No match arm matched value: 3. Add a wildcard: _ => ..."match 3 { 1 => "one" 2 => "two"};Nested match
Section titled “Nested match”Match expressions can be nested inside block bodies for multi-level dispatch.
fn articulation(instrument, velocity) { match instrument { "strings" => { match velocity { v if v > 100 => "marcato" v if v > 60 => "detaché" _ => "pizzicato" } } "brass" => { match velocity { v if v > 100 => "sforzando" v if v > 60 => "sustained" _ => "muted" } } _ => "default" }}
PRINT articulation("strings", 120); // "marcato"PRINT articulation("strings", 40); // "pizzicato"PRINT articulation("brass", 80); // "sustained"Matchable types
Section titled “Matchable types”Practical examples
Section titled “Practical examples”MIDI velocity description
Section titled “MIDI velocity description”fn describe_velocity(vel) { match vel { v if v > 100 => "fortissimo" v if v > 80 => "forte" v if v > 60 => "mezzo-forte" v if v > 40 => "piano" _ => "pianissimo" }}
for v in #[30, 64, 90, 120] { PRINT f"{v} -> {describe_velocity(v)}";}// 30 -> pianissimo// 64 -> mezzo-forte// 90 -> forte// 120 -> fortissimoScale routing
Section titled “Scale routing”Match a mode name to select scale intervals.
fn scale_intervals(mode) { match mode { "ionian" => #[0, 2, 4, 5, 7, 9, 11] "dorian" => #[0, 2, 3, 5, 7, 9, 10] "phrygian" => #[0, 1, 3, 5, 7, 8, 10] "mixolydian" => #[0, 2, 4, 5, 7, 9, 10] "aeolian" => #[0, 2, 3, 5, 7, 8, 10] _ => #[0, 2, 4, 5, 7, 9, 11] }}
let intervals = scale_intervals("dorian");PRINT intervals; // #[0, 2, 3, 5, 7, 9, 10]Drum dispatch
Section titled “Drum dispatch”Map General MIDI drum note numbers to names using note–number coercion.
fn drum_label(n) { match n { C2 => "kick" D2 => "snare" Fs2 => "hi-hat closed" As2 => "hi-hat open" C3 => "high tom" _ => f"drum {n}" }}
for note in #[36, 38, 42, 46, 48, 99] { PRINT f"{note}: {drum_label(note)}";}// 36: kick// 38: snare// 42: hi-hat closed// 46: hi-hat open// 48: high tom// 99: drum 99