Generated by keal doc from the prelude — the signatures below are the compiler's own.
trait Add
func plus(other: Self): Self
trait Sub
func minus(other: Self): Self
trait Mul
func times(other: Self): Self
trait Div
func div(other: Self): Self
trait Rem
func rem(other: Self): Self
trait Neg
func negate(): Self
trait Pow
a ** b is a.pow(b) — power, right-associative, tighter than *.
func pow(other: Self): Self
trait Root
a ^/ b is a.root(b) — the b-th root, the inverse of **. (//
belongs to comments, so the root wears the power's hat.)
func root(other: Self): Self
trait Eq
Structural equality. Without it, == on two instances compares identity,
so two separately built values are never equal.
func equals(other: Self): Bool
trait Index
a[i] reads through get, and a[i] = v writes through set.
The trait carries no signature of its own, and that is deliberate: what
a class is indexed *by* and what it gives *back* differ from class to
class, and a trait here cannot yet hold those two types. So the trait
says a class is indexable and the class's own get says with what. The
checker holds it to that: a class declaring Index must have a get
taking one argument, and a set — which makes a[i] = v legal — must
take that same key type and the value get returns.
trait Invoke
a(x, y) calls through invoke.
Same reasoning as Index: the parameters and the result are the class's
own, and the trait only says that calling one is meaningful.
trait Ord
A total order. compareTo answers less, equal or greater according
as the receiver sorts before, with, or after other — the question being
asked, rather than a number to compare against zero.
func compareTo(other: Self): Comp
func compare<T: Ord>(a: T, b: T): Comp
Compares two values of any ordered type — Int, Float, String, or
your own : Ord class — as a Comp.
record Tuple2<A, B>(val first: A, val second: B)
val first: A
val second: B
record Tuple3<A, B, C>(val first: A, val second: B, val third: C)
val first: A
val second: B
val third: C
record Tuple4<A, B, C, D>(val first: A, val second: B, val third: C, val fourth: D)
val first: A
val second: B
val third: C
val fourth: D
record Tuple5<A, B, C, D, E>(val first: A, val second: B, val third: C, val fourth: D, val fifth: E)
val first: A
val second: B
val third: C
val fourth: D
val fifth: E
class SeqIter<T>(val hasNextFn: () -> Bool, val nextFn: () -> T)
One pass over a sequence: whether an element remains, and the next one.
Calling nextFn without a true hasNextFn first is the caller's bug.
val hasNextFn: () -> Bool
val nextFn: () -> T
class Sequence<T>(val iterFn: () -> SeqIter<T>)
A recipe for iteration. Each terminal operation asks iterFn for a
fresh pass, so a sequence built from a stable source can be walked twice.
val iterFn: () -> SeqIter<T>
func iterator(): SeqIter<T>
func map<R>(transform: (T) -> R): Sequence<R>
Transforms each element as it is pulled.
func filter(predicate: (T) -> Bool): Sequence<T>
Keeps the elements the predicate accepts. One element of lookahead,
held in a one-slot buffer, is what makes hasNext honest.
func take(n: Int): Sequence<T>
At most n elements, then stops pulling.
func drop(n: Int): Sequence<T>
Skips the first n elements, lazily: nothing is pulled until the
downstream asks.
func takeWhile(predicate: (T) -> Bool): Sequence<T>
Elements while the predicate holds; the first refusal ends the sequence and nothing after it is pulled.
func dropWhile(predicate: (T) -> Bool): Sequence<T>
Skips the leading run the predicate accepts, keeps everything after.
func flatMap<R>(transform: (T) -> Sequence<R>): Sequence<R>
Substitutes a whole sequence for each element and flattens, still pulling one element at a time.
func toList(): List<T>
proc forEach(action: (T) -> Unit)
func fold<R>(initial: R, operation: (R, T) -> R): R
func count(): Int
func any(predicate: (T) -> Bool): Bool
True as soon as one element passes; pulls no further.
func all(predicate: (T) -> Bool): Bool
False as soon as one element fails; pulls no further.
func first(): T?
The first element, or null for an empty sequence.
class Set<T>() : Index
A set: membership, without order and without duplicates.
Backed by a map, because a map is already a hash table and a set is a map that only ever answers yes or no. Anything a map can key, a set can hold.
var seen: Map<T, Bool>
func get(value: T): Bool
Whether the value is in the set. Also s[x], through Index.
proc add(value: T)
Adds a value. Adding one already there changes nothing, which is what makes a set a set.
proc set(value: T, present: Bool)
s[x] = true adds, s[x] = false removes — so a set reads and
writes with the same two brackets a list does.
proc remove(value: T)
func size(): Int
func isEmpty(): Bool
func toList(): List<T>
The values, in the order they were first added.
func setOf<T>(xs: List<T>): Set<T>
A set holding everything in xs, duplicates collapsed.
class Deque<T>()
A double-ended queue: add and take at either end, without the cost.
A list can do this already — add at the back, removeAt(0) at the
front — but removeAt(0) moves every remaining element, so a queue
built that way costs the square of its length. This one keeps a head
index and only compacts when the wasted front is most of the buffer, so
taking from the front is what it looks like.
var items: List<T>
var head: Int
func size(): Int
func isEmpty(): Bool
proc addLast(value: T)
proc addFirst(value: T)
Adding at the front is the one operation that must move things, and it is the rare one; a queue is filled at the back.
func removeFirst(): T?
The front value, removed. Null when there is nothing to take — which is a question, not a failure, so it is answered rather than thrown.
func removeLast(): T?
func first(): T?
func toList(): List<T>
func dequeOf<T>(xs: List<T>): Deque<T>
A queue holding everything in xs, front first.
func distinct<T>(xs: List<T>): List<T>
The values of xs, first occurrence kept, duplicates dropped.
func zip<A, B>(a: List<A>, b: List<B>): List<Tuple2<A, B>>
Pairs off two lists, stopping at the shorter.
func partition<T>(xs: List<T>, keep: (T) -> Bool): Tuple2<List<T>, List<T>>
Splits xs in two: what satisfies the test, and what does not. One
pass, and both halves come back — which is what a pair of filters
costs twice over.
func chunked<T>(xs: List<T>, n: Int): List<List<T>>
xs cut into runs of n, the last one short if it has to be.
func padStart(s: String, width: Int, pad: String): String
s with pad repeated in front until it is width wide. A string
already that wide comes back unchanged — padding never truncates.
func padEnd(s: String, width: Int, pad: String): String
The same, at the end.
func lines(s: String): List<String>
The lines of s, without their newlines. A trailing newline does not
make a last empty line — a file ending in one has as many lines as it
looks like it has.
record DateTime(val year: Int, val month: Int, val day: Int, val hour: Int, val minute: Int, val second: Int, val weekday: Int, val offset: Int)
A moment, in the pieces a person reads, and how far east of UTC they
were read. offset is 0 for UTC, 7200 for a summer in Paris.
val year: Int
val month: Int
val day: Int
val hour: Int
val minute: Int
val second: Int
val weekday: Int
val offset: Int
func iso(): String
ISO 8601, to the second: 2026-09-01T14:23:05Z, or
2026-09-01T16:23:05+02:00 away from UTC. The suffix is not
decoration — it is the claim about which clock these numbers are on,
and it is true either way.
func zone(): String
Z, or +02:00, or -05:30.
func date(): String
2026-09-01
func clock(): String
14:23:05
func toString(): String
func epochSeconds(): Int
Back to seconds since the epoch, so a moment can make a round trip. The offset comes off again: these numbers are on a local clock, and the epoch is not.
func inUtc(): DateTime
The same moment, read on the UTC clock.
func inLocalTime(): DateTime
The same moment, read on this machine's clock.
func twoDigits(n: Int): String
func floorDiv(a: Int, b: Int): Int
Floor division, which is what a calendar needs: Keal's / truncates
toward zero, and a moment before 1970 would land on the wrong day.
func floorMod(a: Int, b: Int): Int
func utcAt(seconds: Int): DateTime
The moment seconds after the Unix epoch, in UTC.
The calendar arithmetic is Howard Hinnant's civil_from_days, which is
exact for every year a 64-bit count of seconds can reach, and has no
table and no leap-second fudge in it.
func localAt(seconds: Int): DateTime
The moment seconds after the epoch, read on this machine's clock.
The offset is asked for that instant, not for now: a moment in July and a moment in January are on different sides of a daylight-saving change in most of the world, and a calendar that asks "what is the offset today" gets the other half of the year wrong by an hour.
func localNow(): DateTime
The moment this is called, on this machine's clock.
func daysFromCivil(year: Int, month: Int, day: Int): Int
The inverse: the day number for a civil date. Hinnant's
days_from_civil, and the exact undoing of the one above.
func utcNow(): DateTime
The moment this is called, in UTC.
func monthName(month: Int): String
The names, for a program that wants to print one. January is 1, and Sunday is 0, so both are indexed the way the fields are numbered.
func weekdayName(weekday: Int): String
func isLeapYear(year: Int): Bool
Whether a year has a 29th of February, by the rule the calendar above already obeys.
func exists(path: String): Bool
Whether anything is at path at all.
func isFile(path: String): Bool
Whether path names something that can be read with readFile.
func isDir(path: String): Bool
Whether path names a directory, which is what listDir will open.
func walkDir(path: String): List<String>
Every file under path, depth first, each as a path that can be read.
Directories are walked rather than listed, so what comes back is what
readFile will open; the order is listDir's, which is sorted, so two
runs over the same tree agree.
A path that is not a directory yields nothing rather than failing: a walk over what is not there is empty, which is what the caller would have written anyway.
func seq<T>(xs: List<T>): Sequence<T>
A sequence over a list. The list is read as the sequence is pulled, one index at a time.
func iterate<T>(seed: T, step: (T) -> T): Sequence<T>
The infinite sequence seed, step(seed), step(step(seed)), .... Pair it
with take or takeWhile; a plain toList on it will not come back.
class ActorRef<M>(val mailbox: List<M>)
The address of an actor: something to send to. Holds only the mailbox,
so references never form cycles through the system.
val mailbox: List<M>
proc send(msg: M)
Enqueues a **copy** of the message and returns immediately;
delivery happens inside run. Messages cross by copy on every
engine — under real threads they cross heaps, and the semantics
must not depend on the scheduler — so mutating a value after
sending it never reaches the receiver. An ActorRef inside a
message is the exception: an address is shared, not duplicated.
class Outbox<T>(val items: List<T>)
Where results leave the actor world: an outbox is an **address**, like
an ActorRef — capturing one shares it rather than copying it, so
actors post into the same box the spawner drains after run. Under a
threaded scheduler the posts interleave; treat the contents as a bag
unless one actor alone is posting.
val items: List<T>
proc post(v: T)
func drain(): List<T>
Everything posted so far, in arrival order — as **copies**: what leaves the box is yours alone, so draining twice aliases nothing, on any scheduler.
func outbox<T>(): Outbox<T>
An empty outbox; Outbox<Int>([]) written the readable way.
class ActorSystem<M>()
A set of actors and their mailboxes. spawn registers a handler; run
delivers until every mailbox is empty.
var handlers: List<(ActorRef<M>, M) -> Unit>
var mailboxes: List<List<M>>
func spawn(handler: (ActorRef<M>, M) -> Unit): ActorRef<M>
A new actor. The handler receives the actor's own ref — for replies and self-sends — and one message; its state lives in what the handler's closure captured, and **each actor gets its own copy of every capture**: an actor's state is its own, on every engine, so mutating a captured value after the spawn never reaches the actor, and two actors never share one. Aggregate the actor way — reply with messages — not through a captured collection.
proc run()
Delivers until every mailbox is drained and no handler is running.
The interpreters deliver round-robin — one message per actor per
pass, in spawn order — deterministically; compiled natively, each
actor is an OS thread and only the order *within* one actor's
mailbox is promised, which is the only order the model ever
promised. A handler's panic ends run on the calling thread, so
try { sys.run() } catches it on every engine.