Pattern Matching
BioLang's match expression tests a value against a series of patterns.
It supports literal patterns, variable binding, wildcard _, guard clauses,
or-patterns with |, and enum variant destructuring.
match is an expression — it returns the value of the matching branch.
Basic Match
The first matching arm wins. Use _ as a catch-all:
# Match on string values
let base = "A"
let name = match base {
"A" => "Adenine",
"T" => "Thymine",
"C" => "Cytosine",
"G" => "Guanine",
_ => "Unknown"
}
println(name)
Literal Patterns
Match against integers, floats, strings, and booleans:
# Integer patterns
let code = 2
let label = match code {
1 => "low",
2 => "medium",
3 => "high",
_ => "unknown"
}
println(f"Code {code} = {label}")
# Boolean patterns
let paired = true
let msg = match paired {
true => "paired-end sequencing",
false => "single-end sequencing"
}
println(msg)
Variable Binding
An identifier in a pattern binds the matched value to that name inside the arm:
# The variable 'x' captures the matched value
let val = 42
let result = match val {
0 => "zero",
x => f"got: {x}"
}
println(result)
Guard Clauses
Add if conditions after a pattern for fine-grained control.
The guard is evaluated only when the pattern matches:
# Classify a score using guards
let classify = |score| match score {
s if s >= 90 => "A",
s if s >= 80 => "B",
s if s >= 70 => "C",
_ => "F"
}
[95, 82, 71, 55] |> each(|s| println(f"{s} => {classify(s)}"))
Or Patterns
Combine multiple patterns with | to share a branch:
# Multiple values map to the same result
let bases = ["A", "G", "C", "T", "U"]
bases |> each(|b| {
let kind = match b {
"A" | "G" => "purine",
"C" | "T" | "U" => "pyrimidine",
_ => "unknown"
}
println(f"{b} is a {kind}")
})
Enum Variant Patterns
Match on string values for classification:
let variant_type = "missense"
let impact = match variant_type {
"frameshift" => "HIGH",
"nonsense" => "HIGH",
"missense" => "MODERATE",
"synonymous" => "LOW",
_ => "UNKNOWN"
}
println(f"Impact: {impact}")
Match as an Expression
Since match returns a value, it can be used anywhere an expression is expected:
# Use match in a map pipeline
let scores = [95, 72, 88, 45, 91]
let grades = scores |> map(|s| match s {
s if s >= 90 => "A",
s if s >= 80 => "B",
s if s >= 70 => "C",
_ => "F"
})
println(grades)
match with type()
Combine type() with match to dispatch on value types:
# Describe the type of a value
let describe = |x| match type(x) {
"Int" => f"integer: {x}",
"Float" => f"float: {x}",
"String" => f"string: {x}",
"List" => f"list with {len(x)} items",
_ => f"other: {x}"
}
println(describe(42))
println(describe(3.14))
println(describe("hello"))
println(describe([1, 2, 3]))
Wildcard Pattern
The underscore _ matches any value without binding it.
Always include a _ arm to handle unexpected cases:
# Catch-all for unrecognized input
let enzyme = |site| match site {
"GAATTC" => "EcoRI",
"AAGCTT" => "HindIII",
"GGATCC" => "BamHI",
_ => "unknown"
}
["GAATTC", "GGATCC", "AAAA"] |> each(|s| println(f"{s} => {enzyme(s)}"))
Nested Match
Match expressions can be nested or used inside pipe chains for complex branching:
# Classify and filter in a pipeline
let data = [
{name: "TP53", impact: "HIGH"},
{name: "BRCA1", impact: "MODERATE"},
{name: "TTN", impact: "LOW"},
{name: "EGFR", impact: "HIGH"},
]
let priorities = data |> map(|v| {
let pri = match v.impact {
"HIGH" => 3,
"MODERATE" => 2,
_ => 1
}
{name: v.name, priority: pri}
})
priorities
|> filter(|p| p.priority >= 2)
|> each(|p| println(f"{p.name}: priority {p.priority}"))