Chapter 8
The prelude
Every program has these in scope; any definition of your own with the same name replaces the prelude's.
Types: Option(a) = None | Some(a), Result(a, e) = Ok(a) | Err(e), List(a) = Nil | Cons(head, tail).
Lists: map filter fold len sum range reverse append take drop nth any all find index_of has count last each zip zip_with unzip fst snd enumerate take_while drop_while partition flatten flat_map chunks distinct group_by min_by max_by sort sort_by sort_with
sort is a stable merge sort by <; sort_by(l, key) orders by what key gives, and sort_with(l, before) by before(a, b), whether a may come before b — <=, not <, or equal elements would swap. group_by(l, key) gives (key, members) pairs in the order the keys were first seen. Each of these stands on its own, so a program that defines a find of its own loses the prelude's find and nothing else.
Option/Result: unwrap_or opt_map res_map ok_or map_err
Maps: map_get map_or map_has map_keys map_values map_items map_of
Channels: recv_opt(ch) -> Option(a)
Signals: sig_hup() sig_int() sig_term() — the numbers wait_signal answers with
Standard error: eprintln(x) eprint(x) — what println and print do, on standard error, unbuffered
Numbers: max min abs
Strings: join repeat split lines trim contains starts_with
Strands: apart(x) — x, and the claim that strands share it on purpose; see What strands may share
Characters: char_count char_at char_sub char_take char_drop chars from_char from_chars char_decode char_wide — see Characters; chr is a byte
IO: args() (program name included), read_file(path) -> Result(Str, Str), open_file(path, mode) -> Result(Int, Str), dir_names(path) -> List(Str), replace_file(path, text) -> Result(Int, Str)
The libraries
What the prelude does not have is in lib/, on the search path of every program in the project, imported by path and usually under a name:
import "text/str" as s |
strings past the prelude: searches, transforms, parsers, every encoding, strands over a long text |
import "data/json", "yaml" |
the two formats, read and written |
import "web/http" as h, "ws" |
an HTTP/1.1 server with middleware, and WebSocket over it |
import "web/tls" as tls |
TLS over a socket through OpenSSL: https:// as a client, verified, and served with a certificate |
import "web/url" as url |
a URL taken apart and put together, a query as pairs, a reference resolved against a base |
import "web/mime" as mime |
the media type a file is served as, from its name |
import "web/form" as form |
what a <form> sends: urlencoded pairs, or multipart parts with their files |
import "net/udp" as udp |
datagrams, sent and received whole, a receive parking the strand |
import "net/dns" as dns |
a name to its addresses through the system's resolver, without holding a worker |
import "num/grid" as g |
arrays of numbers with a shape, as NumPy has them |
import "db/kv" |
a key–value store on disk: a B+ tree, a page cache, a log |
import "crypto/sha1", "passwd" |
SHA-1 and base64; storing a password so it cannot be read back |
import "crypto/sha2" as sha |
SHA-256 and SHA-512, HMAC over each, a tag compared in constant time |
import "data/checksum" as ck |
CRC-32 and Adler-32, whole or in pieces |
import "data/csv" as csv |
CSV as RFC 4180 has it, read to rows or records and written back |
import "data/deflate" as z |
DEFLATE both ways, and gzip and zlib around it |
import "time/clock" as clock |
elapsed time, a timed call, a duration in words |
import "time/date" as date |
civil dates and times in UTC: the counts, the calendar, ISO 8601 |
import "text/regex" as re |
regular expressions: a backtracking matcher with groups |
import "text/path" as path |
file paths as text: join, take apart, normalize |
import "text/fmt" as fmt |
a template with slots, padding by width, a float to so many places, thousands, bytes, ordinals, a table |
import "random/rnd" as rnd |
PCG32: a generator that is a value, and the draws made from it |
import "random/uuid" as uuid |
UUIDs, random (v4) and time-ordered (v7), from the operating system's entropy |
import "cli/args" as cli |
what a program takes on its command line, said once, parsed and explained |
import "cli/env" as env |
environment variables, the working directory, the machine's name, the process id |
import "cli/proc" as proc |
running a command: its output and exit code, a line built with each argument quoted |
import "cli/log" as log |
a logger that is a value: the time, the level, the name, on standard error |
import "num/decimal" as dec |
decimals with a fixed number of places, for money |
import "num/bigint" as big |
integers of any size |
import "coll/set" as set |
a set of any key-able value, as storage like Map; union, intersection, difference |
import "coll/heap" as heap |
a priority queue that is a value: a leftist heap, by < or by an order given |
import "coll/deque" as dq |
a queue open at both ends that is a value; constant time on average at either |
import "db/oxidb" and friends |
clients for OxiDB's engines |
Each module says at its head what it is for and how it is used, keeps its helpers private, and carries its own tests: rill test lib/text/regex.rill runs them.
Documentation
There is no doc-comment syntax. The comment a declaration has above it — the # lines just before a type, trait, fn, machine or system — is its documentation, and the block after a module line is the module's own, which is how every module in lib/ was written before there was anything to read them. rill doc file.rill turns a file into Markdown: the module's head, its types with their constructors, its traits with their methods, its systems and machines with their diagrams, and its functions with the signatures the checker inferred, private ones left out; rill doc lib -o docs/lib does a folder, one page a module. A program's head comment is the program's, not its first type's, and its main and tests are listed rather than documented.