La bibliothèque standard

Généré par keal doc depuis le prélude — les signatures ci-dessous sont celles du compilateur lui-même.

the standard library

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.