Functions
fn name [shape_params] (params) -> RetType = expr
or
fn name [shape_params] (params) -> RetType { ...; expr }
The block form is the same expression as the = form, just lifted
into a block.
Components
name: identifier; must be unique at module scope.shape_params: optional[N, M, ...]list of shape variables of kindnat. Each may have an explicit: natannotation.params: comma-separatedname: Typepairs. Param types may reference shape parameters.RetType: the return type. Required today.- Body: a single expression. Use a block for multi-step bodies.
Parameters
fn add(a: i32, b: i32) -> i32 = a + b
Parameters are positional; there is no keyword-arg syntax. There is no default value syntax.
Shape parameters
fn dot[N: nat](x: f32[N], y: f32[N]) -> f32 = +/(x .* y)
fn matmul[M, K, N](a: f32[M, K], b: f32[K, N]) -> f32[M, N] = ...
Shape parameters are inferred at the call site. The compiler emits
one specialised copy per binding (dot__3, dot__8, etc.).
Recursion
Self-recursion and mutual recursion are supported because the type checker collects all top-level signatures in a first pass before checking any body.
Lambdas
|x| body
|a, x| body
Lambdas are anonymous functions, used as arguments to higher-order
primitives like tabulate, scan, iterate_until, iterate.
Lambdas do not capture surrounding state; they are inlined at use
sites and exist primarily so the compiler can specialise the
combiner without a separate top-level definition.
Lambda parameter types are inferred from the call context. The return type is the type of the body.
Calls
f(a, b, c)
The number and types of arguments must match. Calls are eager and left-to-right.
Pipeline calls
x |> f // f(x)
x |> f(y) // f(x, y)
x |> f |> g // g(f(x))
|> is left-associative at precedence 1 (the loosest binary
operator — looser than ||, &&, comparisons, and arithmetic).
The piped value always becomes the first argument.
Casts
The as operator is a postfix form on expressions:
let f: f32 = 3.14;
let i: i32 = f as i32;
It is not a function call; it is a special postfix.