Skip to content

Intent Verbs

Functions are declared with a verb that describes their purpose. The verb IS the declaration — no fn or function keyword. The compiler verifies the implementation matches the declared intent.

Verbs are divided into two families: pure (no side effects) and IO (interacts with the outside world).

Pure Verbs

Pure verbs have no side effects. The compiler enforces this. They can be memoized, inlined, and parallelized safely.

Verb Purpose Compiler enforces
creates Creates a new value from a given value No !. Returns a freshly constructed value
derives Non-mutating data access or derivation No !. Never allocates. Non-mutating
transforms Failable version of creates/derives Allows !. Pure but can fail at runtime (deserialization, conversion)
validates Pure boolean check No !. Return type is implicitly Boolean
matches Pure match dispatch on matchable type No !. First parameter must be a matchable type (algebraic, String, Integer, Result, or Option). from block is implicitly a match

Semantic Guarantees

The verb carries strict guarantees that the compiler exploits for optimization:

Verb Allocates? Can fail? Compiler optimization
derives Never Never Freely inlined, reordered, and eliminated. No region scope needed. Best memoization candidate.
creates Always Never Needs allocation but no error handling. Safe to inline.
transforms May Yes (!) Requires error propagation. Conservative optimization only.
validates Never Never Returns Boolean. Same safety guarantees as derives.
matches Never Never Pure dispatch on algebraic type. Same safety guarantees as derives.

Non-allocating pure verbs (derives, validates, matches) cannot accept Mutable parameters — mutation violates purity (E437).

derives never allocates new values. It extracts or recomputes from existing data — the return is always derivable from the input without heap allocation. If a function needs to allocate a new value (even if input and output types match), use creates instead.

Note: reads is accepted as a backward-compatible alias for derives. New code should use derives.

creates always allocates. It constructs a freshly allocated value of a different type. The compiler knows it cannot fail, so no error-handling scaffolding is emitted.

transforms is the only pure verb that can fail. The ! suffix is allowed, and the compiler emits error propagation paths. Because it may allocate and may fail, the optimizer treats it conservatively.

Examples

matches area(s Shape) Decimal
from
    Circle(r) => pi * r * r
    Rect(w, h) => w * h

validates email(address String)
from
    contains(address, "@") && contains(address, ".")

transforms config(data String) Config!
  requires valid toml(data)
from
    Config(toml(data))

creates normalize(data List<Decimal>) List<Decimal>
  ensures len(result) == len(data)
from
    max_val as Decimal = max(data)
    divide_each(data, max_val)

derives length(s String) Integer
from
    count_bytes(s)

creates builder() Builder
from
    allocate_buffer()

IO Verbs

IO verbs interact with the external world. Side effects are explicit in the verb.

Verb Purpose Compiler enforces
inputs Reads/receives from external world IO is inherent. ! marks fallibility
outputs Writes/sends to external world IO is inherent. ! marks fallibility
dispatches IO match dispatch on matchable type First parameter must be a matchable type. IO calls allowed in match arms. from block is implicitly a match
streams Blocking IO loop with implicit match IO is inherent. Body is a single match expression with an Exit() arm

dispatches is the IO counterpart to matches. Use it when you need to pattern-match on a variant and perform IO in each arm (e.g., routing commands to handlers, dispatching messages by type).

Examples

inputs users() List<User>!
from
    query(db, "SELECT * FROM users")!

outputs log(message String)
from
    write(stdout, message)

dispatches parse_command(command Option<String>, arguments List<String>)!
from
    Some("build") => build(arguments)!
    Some("check") => check(arguments)!
    Some("--version") =>
        config as Config = config()!
        console(f"{config.package.version}")
    _ => console(HELP_TXT)

inputs request(route Route, body String, db Store) Response!
from
    match route
        Get(/health) => ok("healthy")
        Get(/users) => users(db)! |> encode |> ok
        Post(/users) => create(db, body)! |> encode |> created
        _ => not_found()

Verb-Dispatched Identity

Functions are identified by the triple (verb, name, parameter types) — not just (name, parameter types). The same function name can be declared multiple times with different verbs:

validates email(address String)
from
    contains(address, "@") && contains(address, ".")

creates email(raw String) Email
from
    lowercase(trim(raw))

inputs email(user_id Integer) Email!
from
    query(db, "SELECT email FROM users WHERE id = {user_id}")!

Three functions, all named email, with completely different intents.

Context-Aware Call Resolution

At call sites, you use just the function name — the compiler resolves which verb-variant to call based on context:

// Predicate context → resolves to validates email
clean_list as List<Email> = filter(inputs, valid email)

// Email context + String param → resolves to creates email
clean as Email = email(raw_input)

// Email context + Integer param → resolves to inputs email
stored as Email = email(user.id)

Resolution rules: 1. valid keyword → explicitly invokes the validates variant (e.g., valid email(address) or valid email as a predicate reference) 2. Expected type from assignment → matches the variant returning that type 3. Parameter types disambiguate between variants with same return type 4. Ambiguous → first matching candidate wins based on arity and parameter types

Parameters

Go-style: name Type (no colon):

matches area(s Shape) Decimal
inputs request(route Route, body String) Response!
validates email(address String)

Body Marker: from

Every function body begins with from. No exceptions:

matches area(s Shape) Decimal
from
    pi * s.radius * s.radius

inputs users() List<User>!
  ensures len(result) >= 0
from
    query(db, "SELECT * FROM users")!

IO and Fallibility

IO is inherent in the verb. Fallibility is marked with ! on the return type. Pure verbs have neither IO nor !:

matches area(s Shape) Decimal
from
    pi * s.radius * s.radius

inputs users() List<User>!
from
    query(db, "SELECT * FROM users")!

outputs write_log(entry String)
from
    append(log_file, entry)

Reads as: "inputs users, returns List of User, can fail!"

See Type System — Error Propagation for how ! works at call sites.

See Contracts for ensures and requires on function signatures.