Types
Enums, records, aliases and opaque types, and the exhaustive match that
takes them apart.
Enums and records
Enums declare variants. Records declare fields. Both are type.
type Stat {
files Int
dirs Int
bytes Int
}
fn totals_for(root String) Nil {
totals = Stat(files: 0, dirs: 0, bytes: 0)
next = Stat(..totals, dirs: totals.dirs + 1)
Stat(files, dirs, bytes) = walk(root)
println('${next.dirs} ${files} ${dirs} ${bytes}')
}
Construction uses labelled arguments. .. spreads an existing record into a
new one. A record pattern in binding position destructures it. Type parameters are
lowercase names, filled in fresh at every use site.
/** A generic enum: a persistent stack, recursive in its own type parameter. */
type Stack(a) {
Empty
Top(head a, rest Stack(a))
}
fn twice(f fn(a) a, x a) a {
f(f(x))
}
Aliases
Aliases name existing types, generic and function types included.
type Path = String
type Bag(a) = Array(a)
type Validate = fn(Int) Result(Int, String)
Opaque types
pub opaque type exports a type and keeps its constructors private, so a
value can only be built through the module's own functions. Wrap domain values this way:
an amount that is its own opaque type cannot be confused with a bare number, and mixing
two currencies becomes a type error.
Pattern matching
match is checked for exhaustiveness. A missing variant is a compile error.
So is an unreachable arm.
type Event {
Click(at Point, button Int)
Key(code Int, shift Bool)
Scroll(dy Int)
Quit
}
pub fn main() {
e = Key(code: 27, shift: False)
label = match e {
// A nested constructor pattern reaches into the payload's payload.
Click(Point(0, 0), _) -> 'click at the origin'
// A guard refines a pattern with a test the pattern cannot express.
Click(Point(x, y), _) if x == y -> 'click on the diagonal at ${x}'
// Fields can be matched by label, and `..` drops the ones not named.
Click(at: p, ..) -> 'click at ${p.x},${p.y}'
Key(27, _) -> 'escape'
Key(code, True) -> 'shift + key ${code}'
Key(code, False) -> 'key ${code}'
Scroll(1) -> 'scroll nudge down'
Scroll(-1) -> 'scroll nudge up'
Scroll(dy) -> 'scroll ${dy}'
Quit -> 'quit'
}
Patterns also cover or-patterns (200 | 201 | 204), end-exclusive ranges
(400..500), string literals ('GET' | 'HEAD'), tuples, arrays
([first, ..rest]), and binaries, covered under
Binaries.