Skip to main content

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 kind nat. Each may have an explicit : nat annotation.
  • params: comma-separated name: Type pairs. 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.