Types
Gale builds richer types from fixed-length tuples, aliases, literal unions,
and recursive algebraic data types. Generic parameters use angle brackets.
Exhaustive case covers every finite shape.
mod types
pub type Pair<A, B> = {A, B}
pub fn make_pair(left: Integer, right: String) -> Pair<Integer, String> { {left, right}}An atom literal such as :ok is also a type containing one value. Joining
literal types with | creates a finite union that case can cover
exhaustively. Boolean is the built-in union :true | :false.
Nilable<T> is shorthand for T | nil; it uses the same union checking and
pattern narrowing rules. It is especially useful for nullable native fields.
mod types
pub fn label(status: :ok | :error) -> String { case status { :ok -> "ok" :error -> "error" }}Guard type tests narrow a broader value inside their arm. Gale emits the native Elixir guard. It does not synthesize guards merely because a function parameter already has a precise type.
mod types
pub fn as_binary(value: Term) -> Option<Binary> { case 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.
mod types
pub type Tree<A> = | Leaf | Node(A, Tree<A>, Tree<A>)
pub fn sum(tree: Tree<Integer>) -> Integer { case tree { Leaf -> 0 Node(n, left, right) -> n + sum(left) + sum(right) }}