Albite

Generics

Generic functions

Type parameters are declared in angle brackets after the name:

fn identity<T>(x: T) -> T {
    x
}

fn const_fn<A, B>(x: A, y: B) -> A {
    x
}

fn compose<A, B, C>(f: B -> C, g: A -> B, x: A) -> C {
    f(g(x))
}

Generic types

Types take parameters the same way:

type Option<T> = None | Some(T)

type Result<T, E> = Ok(T) | Err(E)

type List<T> = Nil | Cons(T, List<T>)

Inference

Type arguments are inferred from the call site:

let x = identity(42);        // T is Nat
let s = identity("hello");   // T is String

Inference also flows from an expected type, which is how a constructor learns its parameters when the value alone does not say:

let none: Option<Nat> = None;
let good: Result<Nat, String> = Ok(42);

None on its own does not determine T — the annotation supplies it. The same applies to a function’s declared return type, so a constructor in tail position usually needs no help.

Explicit type arguments are not yet supported. Turbofish syntax — identity::<Nat>(42) — does not parse. Where inference cannot determine a parameter, annotate the binding or the return type instead, as above. This is the workaround, not a temporary inconvenience with an alternative spelling.

Generic type aliases

Since 1.5

An alias may take parameters, which is useful for naming a recurring instantiation:

pub type ParseResult<T> = Result<(T, Cursor), ParseError>

ParseResult<Nat> then means Result<(Nat, Cursor), ParseError>. This is a genuine convenience in code that threads one shape through many functions:

fn parse_nat(input: Nat, cur: Cursor) -> ParseResult<Nat> {
    Ok((input, cur + 1))
}

An alias introduces no new type — it is the same type under a shorter name, so values flow between the two spellings freely.