Skip to content

Types

Gale builds richer types from fixed-length tuples, transparent aliases, literal unions, and recursive algebraic data types. Generic parameters use angle brackets, and exhaustive match handles every finite shape.

module types
pub type Pair<A, B> = (A, B)
pub fn make_pair(left: Integer, right: Binary) -> Pair<Integer, Binary> {
(left, right)
}

An atom literal such as :ok is also a type containing one value. Joining literal types with | creates a finite union that match can cover exhaustively. Boolean is the built-in union :true | :false.

module types
pub fn label(status: :ok | :error) -> Binary {
match status {
:ok -> "ok"
:error -> "error"
}
}

Guard type tests refine broader values inside their arm. Gale emits the native Elixir guard; it does not synthesize guards merely because a function parameter already has a precise type.

module types
pub fn as_binary(value: Term) -> Option<Binary> {
match value {
binary when is_binary(binary) -> Some(binary)
_ -> None
}
}

An algebraic data type names its constructors and their payloads. ADTs can be recursive: Tree<A> contains either Leaf or a node holding a value and two more trees. Nullary constructors emit snake-case atoms; constructors with payloads emit tagged tuples.

module types
pub type Tree<A> =
| Leaf
| Node(A, Tree<A>, Tree<A>)
pub fn sum(tree: Tree<Integer>) -> Integer {
match tree {
Leaf -> 0
Node(n, left, right) -> n + sum(left) + sum(right)
}
}