Skip to content

Standard library

gale_std provides typed interfaces to common Elixir and OTP functionality. Add it to the dependency list in mix.exs, then alias the modules you use:

{:gale_std, git: "git@github.com:cloudloom-ai/gale.git", branch: "main", subdir: "libs/gale_std"}
alias gale_std.list
alias gale_std.option
alias gale_std.string

Use this page to find a module, understand its return values, and choose common operations. For every function’s signature and documentation, see the standard-library source.

I need to… Module
Work with an optional value gale_std.option
Transform or recover from a result gale_std.result
Process a list gale_std.list
Process values lazily gale_std.stream
Work with maps, sets, or keyword lists gale_std.map, gale_std.map_set, gale_std.keyword
Work with UTF-8 text or raw bytes gale_std.string, gale_std.binary
Convert numbers and atoms gale_std.integer, gale_std.float, gale_std.atom
Work with an Elixir integer range gale_std.range
Validate dynamic data or JSON gale_std.decode, gale_std.json
Read files and paths gale_std.file, gale_std.path
Work with dates, URIs, and time gale_std.date, gale_std.date_time, gale_std.uri, gale_std.time
Print, inspect, or log gale_std.io, gale_std.inspect, gale_std.logger
Read environment values or use crypto gale_std.system, gale_std.crypto
Start processes and exchange messages gale_std.process
Build OTP services gale_std.gen_server, gale_std.supervisor, gale_std.application
Run tasks or dynamic children gale_std.task, gale_std.task_supervisor, gale_std.dynamic_supervisor
Use Registry, ETS, or persistent term gale_std.registry, gale_std.ets, gale_std.persistent_term
Write Gale tests gale_std.test

Option<A> represents presence or absence. Use case with Some(value) and None, or use gale_std.option:

Function Result
is_some?, is_none? Test which constructor is present
unwrap_or(option, default) Return the value or a fallback
map(option, transform) Transform Some; preserve None
and_then(option, transform) Chain a function returning Option
flatten(option) Remove one nested Option layer
from_nil(value), to_nil(option) Convert at Elixir nil boundaries
to_result(option, error) Convert to Result<A, E> with a caller-chosen error

Result<A, E> represents expected success or failure. Use case with Ok(value) and Error(reason), chain results with with, or use gale_std.result:

Function Result
is_ok?, is_error? Test which constructor is present
unwrap_or(result, default) Return the success value or a fallback
map(result, transform) Transform Ok; preserve Error
map_error(result, transform) Transform the error
and_then(result, transform) Chain a function returning Result
to_option(result) Keep an Ok value and discard an error as None

Prefer Option when absence is expected and needs no reason. Prefer Result when the caller needs to know why an operation failed.

Use gale_std.list to construct, inspect, transform, search, and aggregate lists. Gale has no Enumerable protocol, so each collection module owns its operations and lazy traversal stays in gale_std.stream.

Task Common operations
Construct or rearrange a list list.range, list.duplicate, list.reverse, list.flatten
Read an element list.first, list.last, list.at
Transform or filter list.map, list.flat_map, list.filter, list.reject
Search or test list.find, list.any?, list.all?, list.member?
Accumulate a value list.reduce, list.reduce_while, list.sum
Sort or group list.sort, list.sort_by, list.group_by, list.frequencies
Split or combine list.take, list.drop, list.chunk_every, list.zip

list.first, list.find, list.min, and list.max return Option when an element may be absent.

names = users
|> list.filter(fn(user) -> user.active)
|> list.map(fn(user) -> user.name)
|> list.sort()

gale_std.stream.Stream<A> is lazy and distinct from List<A>. Build a stream with from_list, transform it with map, filter, take, or each, then consume it with to_list, reduce, or into_file.

first_ten = values
|> stream.from_list()
|> stream.map(fn(value: Integer) -> value * 2)
|> stream.take(10)
|> stream.to_list()

Use gale_std.map for Map<K, V> values:

Operation Result
get(map, key) Option<V>; distinguishes a missing key from a stored nil
get(map, key, default) The stored value or the default
put(map, key, value) A map with the key inserted or replaced
delete(map, key) A map without the key
pop(map, key) The optional value and the remaining map
keys(map), values(map), to_list(map) Lists of keys, values, or key-value tuples

The module also supports merging, filtering, and updating values with a function.

gale_std.map_set.MapSet<A> is the typed Elixir set. The module provides construction, membership, insertion, deletion, union, intersection, difference, size, and list conversion.

gale_std.keyword works with List<{Atom, V}> and provides typed keyword lookup and updates.

String is UTF-8 text and Binary is arbitrary bytes. A String can be used where a Binary is expected. Converting bytes to text requires validation:

case string.from_binary(bytes) {
Ok(text) -> string.upcase(text)
Error(:invalid_utf8) -> "invalid text"
}
Task Common operations in gale_std.string
Validate bytes as text valid?, from_binary
Inspect text length, empty?, contains?, starts_with?, ends_with?
Transform text trim, upcase, downcase, replace
Split or combine split, graphemes, codepoints, join
Read part of a string first, last, at, slice

gale_std.binary provides byte-oriented byte_size, part, and append. Use gale_std.integer and gale_std.float for numeric conversion, parsing, predicates, and bounds. Float add, subtract, multiply, and divide return Result<Float, gale_std.number.ArithmeticError> and handle arithmetic overflow; divide also handles both signed zero divisors. Binary Float arithmetic operators are rejected so these failures stay values. gale_std.number owns this shared native error type for both integer and Float operations. gale_std.atom.to_existing converts text without creating a new atom.

A decode.Decoder<A> is a function from Term to Result<A, decode.DecodeError>. Primitive decoders include string, binary, integer, float, and boolean. Compose them with list, dictionary, field, optional_field, nullable, map, and and_then.

pub fn user_decoder() -> decode.Decoder<%{name: String, age: Integer}> {
fn(input) -> with {
name <- decode.field(input, "name", decode.string())
age <- decode.field(input, "age", decode.integer())
%{name: name, age: age}
}
}

decode.field requires the field. decode.optional_field permits it to be absent. decode.nullable accepts JSON null and returns None; it does not make an object field optional.

gale_std.json.parse(text, decoder) distinguishes malformed JSON from a valid JSON value with the wrong shape. For output, build the closed Json type with string, integer, float, boolean, null, array, and object, then use encode or encode_with. See the Decoding tour for a complete encoder and decoder.

gale_std.file.read returns bytes. Use read_text when the file must be valid UTF-8. write accepts bytes; a String is accepted because it is a subtype of Binary. The module also provides existence checks, directory creation and removal, file removal, and lazy stream_lines and stream_bytes.

gale_std.path joins and inspects path components. gale_std.system.get_env returns Option<String>. Use gale_std.date and gale_std.date_time for dates, gale_std.uri for URIs, gale_std.time for clocks, and gale_std.crypto for cryptographic operations.

Use gale_std.io for terminal input and output, gale_std.inspect.inspect to turn any Term into text, and gale_std.logger for Logger levels and metadata.

gale_std.process.Pid<M> carries the type of messages a process accepts. spawn and spawn_link create typed processes; self returns a Pid matching the current function’s receives declaration; send accepts only the Pid’s message type.

The module also provides links, monitors, timers, exits, make_ref, and native Down and ExitEvent message types. AnyPid can identify a process for these operations but cannot be used to send an arbitrary message.

gale_std.gen_server.Server<Args, State, Call, Cast, Info, Continue> describes a native GenServer. Call is a reply-indexed request type, so each request constructor determines the result of gen_server.call.

pub type Request<Reply> =
| Count : Request<Integer>
| Add(amount: Integer) : Request<Integer>
pub fn count(server: CounterTarget) -> Integer {
gen_server.call(server, Count)
}

The module exposes typed start_link, child_spec, call, cast, send, reply, stop, names, and lookup. CallServer, CastServer, and Worker aliases fill unused protocols with Never. See the OTP tour for a complete implementation.

gale_std.supervisor and gale_std.application expose native OTP behaviours through declares and implements. Child specifications and return values keep their normal Elixir representations. gale_std.dynamic_supervisor manages children at runtime.

gale_std.task.Task<A> tracks the result type of a task. Use task.async for short caller-owned work and gale_std.task_supervisor for supervised typed tasks. These are native Task and Task.Supervisor processes with compile-time type parameters.

These modules track resource identity and value types at compile time. The type parameters add no runtime wrapper:

Type Tracks
Registry<Name, Key, Value> Registry identity, key type, and stored value
Ets<Name, Key, Value> Table identity, key type, and stored value
PersistentKey<Value> The value associated with a persistent key

Operations that declare raises ArgumentError return a Result for that exception. Check the function signature for its error type.

Gale test modules live under test/, end in _test, and expose public zero-argument functions as ExUnit tests. gale_std.test includes assert, refute, assert_equal, assert_not_equal, assert_raises, assert_exit, assert_log, and start_supervised.

mod shop.total_test
alias gale_std.test
alias gale_std.list
pub fn adds_prices() -> :ok {
test.assert_equal(list.sum([10, 20]), 30)
}

Assertions are ordinary library functions. Runtime type checks are enabled in tests through gale: [runtime_typechecks: Mix.env() == :test] in mix.exs.

The standard library preserves native BEAM values: lists remain lists, maps remain maps, Pids remain Pids, and OTP functions keep their conventional return shapes. Type parameters on processes and resources are compile-time contracts; they are erased at runtime. Foreign Elixir code must obey those contracts.

Expected native exceptions are converted only where an API declares raises E. Exits and undeclared exceptions retain their native behaviour. For the exact model, see trusted typed interfaces.