A short tour of the standard library. Each module's full reference is its own page under @link["modules/index.html"]{Modules}.
@subsection{std/prelude}
The prelude is what every module has without importing anything: the collections and their functions, strings and characters, files and ports, Concurrent ML and scopes, and the macros the language is written with, such as @code{cond}, @code{if-let} and @code{type/derive}. Its reference also covers the builtins, the functions compiled into the runtime rather than written in Bjolang, since every program gets them with the prelude. At the REPL, @code{:show name} prints the same documentation.
For more details, see @link["modules/std/prelude.html"]{@code{(std prelude)}}.
Numbers beyond the operators. Integer division has Racket's names: @code{quotient} and @code{remainder} are what @code{/} and @code{%} do, and @code{modulo} takes the sign of the divisor, so @code{(modulo -1 10)} is 9. There are @code{gcd}, @code{lcm}, an integer @code{expt} and an exact @code{integer-sqrt} at every integer type, the @code{exact-} roundings from a double to an int, and the rest of @code{System.Math} over doubles. The prelude has @code{abs}, @code{min}, @code{max} and @code{clamp} from here without an import.
For more details, see @link["modules/std/maths.html"]{@code{(std maths)}}.
Two modules for numbers in bulk, with the CPU's vector instructions. @code{(std array)} has whole-array operations: @code{array-sum}, @code{array-dot}, @code{array-min}, @code{array-max}, @code{array-add!}, @code{array-scale!}, @code{array-count}, @code{array-index-of} and @code{array-fill!}. Each is one loop in the runtime, which works on as many elements per instruction as a vector register holds when the element is a primitive number, and one at a time for a type such as @code{bigint}. At @code{double}, a sum adds lane by lane, so its last bits can differ from a left fold. @code{(std simd)} has the vectors themselves, for the loops that the kernels do not cover. @code{(Simd128 %a)} and @code{(Simd256 %a)} are .NET's @code{Vector128<T>} and @code{Vector256<T>}, with a name per element type: @code{Float64x4} is four doubles, @code{UInt8x32} is 32 bytes. The operations are the methods of one trait, @code{Simd}, at both widths: @code{simd-add}, @code{simd-mul}, the comparisons @code{simd-lt} and the others, which give masks, @code{simd-select}, @code{simd-count-true}, @code{simd-sum} and more. A vector is made with @code{simd256-load}, @code{simd128-splat} or @code{simd256-zero}, and @code{simd256-whole} says where the elements after the last whole vector start. A 128-bit vector is fast on every x86-64 and ARM64 CPU. A 256-bit vector needs AVX2, and @code{simd256-accelerated?} says whether the CPU has it. The section on performance in "Writing programs" says when vectors pay.
For more details, see @link["modules/std/array.html"]{@code{(std array)}} and @link["modules/std/simd.html"]{@code{(std simd)}}.
Formatting in two layers: interpolation and layout. @code{println*} prints strings, ints, doubles, chars and bools written in one vec. The layout layer is made of blocks: a @code{Block} is one piece of output, and every combinator takes its content as a block and gives back a block. A string, an int and a character are blocks, and so is a vec of blocks, such as @code{["x = " 7 nl]}. With them you pad, cut and align text, wrap and justify paragraphs, format numbers, and lay out tables with borders, a header, and columns that fit the width. The section on formatting text in "Writing programs" is a guide, with what goes in the brackets and what to write when it does not compile.
Bjolang provides a built-in regular expression engine. Unlike languages that use strings for regex (like @code{"[a-z]+"}), Bjolang uses structural S-expressions. This means you never have to double-escape characters, and the compiler validates your patterns at compile time. Built-in character sets and anchors are written as keywords (e.g., @code{:bos}, @code{:digit}), and operations that group or repeat patterns are function-like lists (e.g., @code{(seq ...)}).
Reading a line by a pattern, after OCaml's @code{Scanf}. The pattern is a quoted list of what the line holds, in order: @code{(scan "3-17" '(long "-" long))} is 3 and 17, and @code{'(int "x" int ": " int ... #:sep " ")} reads @code{"12x5: 1 0 3"} as two ints and a vec of them. There are items for numbers, a character, a word, the rest of the line, a run of given characters and the text up to one, with a width, a skip, a repetition, an option and a choice. The type of the result comes from the pattern, so @code{'(int "," int)} gives a @code{(Tuple int int)}. The macro compiles the pattern into straight code over the line's bytes, and a pattern of numbers and strings allocates nothing. The whole line must match. @code{try-scan} gives an @code{Err} that says at which column it failed, instead of raising. A scan does not search and does not backtrack: use @code{(std rx)} to find text in a line.
For more details, see @link["modules/std/scan.html"]{@code{(std scan)}}.
The @code{std/http} module allows you to build and send HTTP requests. Sending a request three ways — blocking, suspending, or as an event — is the only thing that differs between the entry points. There is no C# in this module: @code{System.Net.Http} is reached with @code{import/extern}, and the response body is an ordinary @code{TextInputPort}.
URLs by RFC 3986. A URL is written as a quoted literal, as @code{(std run)} writes a pipeline: @code{(link '(url https "example.com" (path "users" ,name) (query (page 2) (tag ,tag)) (fragment "top")))}, or @code{'(path "users" ,id "edit")} for a path on this site. Each value is encoded for the part that it is in, so a @code{/} in a computed segment does not make a second segment, and a @code{&} in a computed value does not make a second parameter. A grammar reads the literal, so the compiler checks its parts where it is written: a misspelled part, a part given twice, a port out of range or a host that is no host is a compile error. A computed scheme, host or port is made with @code{scheme}, @code{host} or @code{port}, which return a @code{Result}, so @code{make-url} does not fail. @code{parse-url} reads a URL or a relative reference strictly, and refuses text that is not one with the column where it goes wrong. A @code{Url} keeps each part as it was written, so @code{url->string} gives back the same text. @code{url-resolve} reads a link where a page is. @code{url-segments} and @code{url-params} decode the path and the query, and there is one percent-encoder for each part of a URL.
The @code{std/run} module provides a way to run external programs. A form is one thing to run, written as a quoted literal, like @code{'(cat "hej.txt")}. You can connect programs in a pipe with @code{'(pipe (cat "a") (wc -l))}, and redirect input and output to files. Redirections can nest, and you can even splice computed arguments or write stages in Bjolang.
The random module provides a ChaCha20 generator, seeded with 256 bits from the OS CSPRNG, with one generator per thread. The default path locks nothing and shares nothing, making it safe and fast on a bjoroutine. The ambient source has no state to race on, so drawing from multiple threads is efficient. You can generate random integers and more.
Uuids as RFC 9562 specifies them. @code{uuid-v4} is random, for an identifier that must tell nothing. @code{uuid-v7} starts with the time, for a database key: new keys go at the end of an index, and keys sort by when they were made, and the ones made by one process always increase. @code{uuid-v5} is made from a namespace and a name, so the same input gives the same uuid. A @code{Uuid} is 16 bytes and compares as its bytes do, which is also the order of its text and of Postgres' @code{uuid}. @code{uuid->string} writes the one text form, and @code{string->uuid} reads it in either case. The random bits come from @code{current-random} and the time from @code{current-clock}, so a test can make the same uuids in every run.
For more details, see @link["modules/std/uuid.html"]{@code{(std uuid)}}.
@subsection{std/crypto/hash}
Hashes, HMAC and password hashing, from .NET's @code{System.Security.Cryptography}. @code{hash-bytes}, @code{hash-string} and @code{hash-file} make a digest, SHA-256 unless @code{#:algorithm} says otherwise, and @code{make-hasher} makes one a piece at a time. @code{hmac-bytes} and @code{hmac-string} sign a message with a key. A digest is fast, so it is not a password hash: @code{password-hash} uses PBKDF2 with a random salt and gives a PHC string, which holds the algorithm and the iteration count, so @code{password-verify} needs only the password and the string, and @code{password-needs-rehash?} says which to replace after the count is raised. A password hash takes a few hundred milliseconds, and in a bjoroutine it runs on a thread of its own. Compare secrets with @code{constant-time-equal?}, not @code{=}.
For more details, see @link["modules/std/crypto/hash.html"]{@code{(std crypto hash)}}.
An atomic is a cell that threads can read and write without a lock. @code{(make-atomic v)} makes one of any type, and @code{atomic-ref}, @code{atomic-set!}, @code{atomic-swap!}, @code{atomic-compare-and-swap!} and @code{atomic-update!} work on it. For @code{int}, @code{uint}, @code{long} and @code{ulong} there are also @code{atomic-increment!}, @code{atomic-decrement!}, @code{atomic-add!} and @code{atomic-sub!}, which compile to direct calls to @code{System.Threading.Interlocked} and wrap on overflow. Swap and compare-and-swap return the value from before the call; the other operations that change the atomic return the new value. The width of a counter comes from type inference, so write @code{(make-atomic 0L)} for a long counter: @code{(make-atomic 0)} is an int.
For more details, see @link["modules/std/atomic.html"]{@code{(std atomic)}}.
Software transactional memory, after the OCaml library kcas. A @code{(Loc T)} holds one value, and a transaction is a function of a @code{Tx} that reads and writes locations with @code{tx-ref}, @code{tx-set!}, @code{tx-update!} and @code{tx-swap!}. @code{atomically} runs it and commits all of its writes as one step, and runs it again if another transaction changed what it read. @code{tx-retry} stops a transaction until a location that it read changes, and @code{atomically-evt} is the transaction as a CML event, so waiting for a condition combines with timeouts, channels and cancellation in a @code{choose}. @code{tx-or-else} tries alternatives. Three modules build data structures out of locations: @code{(std stm queue)} has the FIFO queue @code{TQueue}, with the channel names @code{queue-send}, @code{queue-recv}, @code{queue-put} and @code{queue-get} outside a transaction; @code{(std stm map)} has the hash map @code{TMap}, whose operations are named as those of the prelude's @code{Map}; and @code{(std stm counter)} has @code{TCounter}, a number that fibers on different CPUs add to without conflicts. Part II has a guide in the section on concurrency.
For more details, see @link["modules/std/stm/"]{@code{(std stm)}}, @link["modules/std/stm/queue.html"]{@code{(std stm queue)}}, @link["modules/std/stm/map.html"]{@code{(std stm map)}} and @link["modules/std/stm/counter.html"]{@code{(std stm counter)}}.
This module provides types and functions for handling time. The clock is an argument (with a default that a program can rebind), and the types refuse operations that mean nothing, such as adding a calendar day to an instant. The module separates @code{Date} (a calendar date without a timezone), @code{Time} (a time of day without a timezone), and @code{DateTime} (a date and time without a timezone), as well as handling timezones.
@code{(std eq)} has the traits @code{Eq} and @code{Ord}. @code{Eq} has @code{=} and @code{eq-hash}, and every type has an implementation: a type with no implementation of its own uses .NET's @code{Equals} and @code{GetHashCode}. @code{Ord} has one method, @code{compare}. The other functions of the module, such as @code{less?}, @code{least}, @code{greatest}, @code{list-sort}, @code{list-min} and @code{list-max}, use only @code{compare}, so a type that implements @code{compare} gets all of them. Strings compare by code point, so the order is the same on every machine. The prelude re-exports every name of @code{(std eq)}, so you do not usually import it. @code{(std clr-ord)} adds @code{Ord} for the .NET time types, @code{Guid} and @code{Version}.
For more details, see @link["modules/std/eq.html"]{@code{(std eq)}} and @link["modules/std/clr-ord.html"]{@code{(std clr-ord)}}.
@subsection{std/monad}
The @code{Monad} trait has @code{pure} and @code{bind}, with instances for @code{List}, @code{Option} and @code{Result}. A @code{(do ...)} block writes a chain of @code{bind} calls as a list of steps: @code{(:bind x e)}, @code{(:let x e)} and @code{(:return e)}. For @code{Option} and @code{Result}, the block stops at the first @code{None} or @code{Err}. For @code{List}, it runs once for each combination of items.
For more details, see @link["modules/std/monad.html"]{@code{(std monad)}}.
@subsection{std/effect}
Effect handlers that resume once. @code{defeffect} declares operations and their default handlers. A call of an operation calls the handler that is installed, and @code{with-handler} installs other handlers for an extent. A test can, for example, collect what the code logs. A handler runs on the stack of the caller, so it can return a value or raise an exception, and nothing else: no continuation is captured. The prelude declares its own effects, such as @code{log}, @code{warn} and the filesystem operations, so you import this module to handle them.
For more details, see @link["modules/std/effect.html"]{@code{(std effect)}}.
@subsection{std/hashset, std/orderedset and std/orderedmap}
Persistent collections beside the prelude's @code{Map}: an update returns a new collection and does not change the old one. @code{(std hashset)} has the unordered @code{HashSet}, a CHAMP trie that compares elements with @code{Eq}. @code{(std orderedset)} and @code{(std orderedmap)} have @code{OrderedSet} and @code{OrderedMap}, B-trees kept in the order of @code{compare}. They add what the order gives: @code{-min}, @code{-max}, @code{-successor}, @code{-predecessor} and the range walks @code{-range}, @code{-from} and @code{-until}. Each collection has a builder, which makes it in one pass, and a transient, which edits it in place and gives it back as a persistent collection in O(1).
For more details, see @link["modules/std/hashset.html"]{@code{(std hashset)}}, @link["modules/std/orderedset.html"]{@code{(std orderedset)}} and @link["modules/std/orderedmap.html"]{@code{(std orderedmap)}}.
A persistent priority queue, least priority first. A @code{(PriorityQueue a p)} holds elements under priorities, and orders the priorities, so the elements need no order of their own. @code{priorityqueue-empty} orders priorities by their @code{Ord}, and @code{priorityqueue-by} by a comparison you give it. Adding or removing gives a new queue and leaves the old one as it was. It is a pairing heap: peeking, adding and @code{priorityqueue-merge} are O(1), and @code{priorityqueue-remove-min} is O(log n) amortised. That bound assumes each queue is used once. Call @code{priorityqueue-balance} on a queue you keep and remove from many times. Entries of equal priority come out in the order they went in. There is a transient and a builder, as for the other persistent collections. For a queue that is used in one place and never shared, @code{(std mutable heap)} is faster.
For more details, see @link["modules/std/priority-queue.html"]{@code{(std priority-queue)}}.
Collections that change in place. Use them for a cache, an index, a worklist or a scratch buffer, where you do not need old versions. @code{(std mutable vec)}, @code{(std mutable map)}, @code{(std mutable set)} and @code{(std mutable heap)} are the .NET @code{List<T>}, @code{Dictionary<K,V>}, @code{HashSet<T>} and @code{PriorityQueue<T,P>} themselves, not wrappers, so .NET code that takes those types accepts them as they are. They compare with .NET's equality and order. @code{(std mutable deque)} is a double-ended queue with O(1) amortized push and pop at both ends. None of them has a lock.
For more details, see @link["modules/std/mutable/vec.html"]{@code{(std mutable vec)}}, @link["modules/std/mutable/map.html"]{@code{(std mutable map)}}, @link["modules/std/mutable/set.html"]{@code{(std mutable set)}}, @link["modules/std/mutable/heap.html"]{@code{(std mutable heap)}} and @link["modules/std/mutable/deque.html"]{@code{(std mutable deque)}}.
@subsection{std/inbox}
An inbox is how .NET code gives work to Bjolang. A thread that is not a fiber, such as a timer, a @code{FileSystemWatcher} or a Kestrel thread, posts an item and returns. A fiber takes the item with its own handlers, parameters and cancellation scope. An inbox always has a capacity, and a @code{WhenFull} policy says what a post does when the inbox is full. @code{inbox-call} is a request and a reply: the .NET caller gets a @code{Task}, and a fiber answers it.
For more details, see @link["modules/std/inbox.html"]{@code{(std inbox)}}.
@subsection{std/ports and std/net}
@code{(std ports)} reads and writes bytes on the prelude's ports. The byte reads @code{read-some-evt}, @code{read-bytes-evt} and @code{eof-evt} are CML events: a read that loses its @code{choose} takes nothing, so a read can race a timeout. @code{read-line} and @code{read-bytes} can be used on the same port. The module also drains ports into lists and vecs, streams them as a @code{Seq} or a channel, and has @code{byte-pipe}, a pair of ports with no file and no network, for tests. @code{(std net)} gives a TCP connection as a pair of these ports, so a protocol written for ports also runs over TCP. @code{accept-evt} is an event too: a branch that loses accepts nothing.
For more details, see @link["modules/std/ports.html"]{@code{(std ports)}} and @link["modules/std/net.html"]{@code{(std net)}}.
@subsection{std/test and std/simpletest}
@code{(std test)} has tests that are silent unless they fail. @code{deftest} registers a test, @code{check} reports the values that it saw when it fails, and @code{(run-tests)} is the @code{main} of the file. Each test runs in a scope with a deadline. The test fails if it leaves a resource open, and the scope waits for the fibers that the test started. @code{bjo test} builds and runs the test files of a project. @code{(std simpletest)} is the older harness: an assertion prints one line, and a failure prints a line that starts with @code{FAILURE:}. Its @code{with-fake-fs}, a filesystem in memory, also works inside a @code{deftest}.
@code{(std test prop)} has property tests. @code{for-all} runs its body many times with generated values. When a run fails, @code{for-all} shrinks it to a small case, reports that case, and stores it beside the test file, so the next run tries it first. @code{assume} discards a run, @code{label} names the failures in its body, and @code{classify} and @code{collect} count the runs for @code{--stats}. @code{(std test gen)} has the generators, and @code{Arbitrary}, which gives the default generator of a type. @code{(std test expect)} has @code{expect-output}, which compares the output of a body with a text in the test, and @code{--promote} updates that text.
For more details, see @link["modules/std/test/"]{@code{(std test)}}, @link["modules/std/test/prop.html"]{@code{(std test prop)}}, @link["modules/std/test/gen.html"]{@code{(std test gen)}}, @link["modules/std/test/expect.html"]{@code{(std test expect)}} and @link["modules/std/simpletest.html"]{@code{(std simpletest)}}.
Benchmarks, written like tests. @code{def/bench} registers a benchmark, with a setup outside the time, parameters that make a row for each combination of values, cold runs for a slow body, and groups. @code{(run-benches)} is the @code{main} of the file. A run warms each benchmark up until its times are steady, calibrates how many calls make a sample, and takes samples until the median is known to ±1%. It prints a table of the median, the spread, the minimum, the allocation and the collections, a row as each benchmark finishes. With no names at a terminal, a menu asks what to run. @code{--save} and @code{--compare} keep a run in a file and compare with it, with p-values corrected for the number of comparisons and a verdict that needs both a significant and a large enough change. @code{bjo bench FILE --against REF} runs a file against itself at a git ref, the two versions measured in turns. @code{time-it} is here too: a body measured in place, on one line.
@code{(std bench stats)} has the statistics: medians, quantiles, bootstrap intervals of a ratio, and the Wilcoxon, Mann–Whitney and t tests, each checked against SciPy. @code{(std bench store)} has saved runs as data, and the two kinds of comparison.
The section on benchmarking in "Writing programs" shows all of it with the card game. For more details, see @link["modules/std/bench/"]{@code{(std bench)}}, @link["modules/std/bench/stats.html"]{@code{(std bench stats)}} and @link["modules/std/bench/store.html"]{@code{(std bench store)}}.
Stopwatches that read the ambient clock, so a test can bind a clock and get an exact time. The module also has @code{time-it}, which is @code{(std bench)}'s: a body measured as a benchmark is, reported on one line.
For more details, see @link["modules/std/stopwatch.html"]{@code{(std stopwatch)}}.
@subsection{std/syntax-match}
@code{syntax-match} takes a form apart with patterns, with @code{...} for repetition. Write macro transformers with it, and build the result with @code{#'}.
For more details, see @link["modules/std/syntax-match.html"]{@code{(std syntax-match)}}.
bjodat is Bjolang's shapes read as data: no evaluation, no macro expansion, no environment. It is what a package manifest, a lockfile, or a config file is written in. You can parse text straight into a record using @code{bjodat-parse-<Name>}, which avoids intermediate trees and allocations. @code{(text bjodat-core)} is the machinery underneath: the @code{Bjodat} tree, with @code{parse-bjodat}, @code{bjodat-ref} and the writer, for data whose shape is not known until the program runs.
For more details, see @link["modules/text/bjodat.html"]{@code{(text bjodat)}} and @link["modules/text/bjodat-core.html"]{@code{(text bjodat-core)}}.
@subsection{text/json and text/json-codec}
@code{(text json)} reads JSON, exactly as RFC 8259 has it, into a @code{Json}: a union with a case for each kind of value. @code{parse-json} reads a string and @code{read-json} a port. A document that is not JSON is an @code{Err} that says the line and column where it went wrong. A number without a fraction or an exponent is a @code{JsonInt}, and an object is a @code{(Map string Json)}, so the order of its keys is not kept. @code{(text json-codec)} reads a record straight from the tree and back: @code{def/json-type} declares a record and the instances of @code{->json} and @code{json->} for it, with defaults, optional fields and other names for the keys. An @code{Option} is @code{null} when it is @code{None}. There is no writer yet, so a @code{Json} cannot be written out as text.
For more details, see @link["modules/text/json.html"]{@code{(text json)}} and @link["modules/text/json-codec.html"]{@code{(text json-codec)}}.
@subsection{text/xml}
XML, in three modules over @code{System.Xml}. @code{(text xml)} is the tree: names, elements, texts, comments and processing instructions, built by @code{xml-element} and the others, and taken apart by views. @code{(text xml read)} reads XML in four layers: a stream of signals, a fold after SSAX, a tree of your own type, and @code{parse-xml}, which gives a @code{Document}. @code{xml-for-each} reads a large document one element at a time. The defaults are the safe ones: a document with a DOCTYPE is refused unless asked for, and nothing external is ever resolved. @code{(text xml write)} writes a node or a document to a port or a string. It chooses the namespace prefixes, and content that XML cannot hold is an @code{XmlWriteError} rather than an exception.
For more details, see @link["modules/text/xml.html"]{@code{(text xml)}}, @link["modules/text/xml/read.html"]{@code{(text xml read)}} and @link["modules/text/xml/write.html"]{@code{(text xml write)}}.
Every character encoding .NET knows, as a value of the prelude's @code{Encoding}, to give to @code{string->bytes} and @code{bytes->string}, or to @code{reencode-input-port} and @code{reencode-output-port} from @code{(std ports)} for a port. There is one for each of the 139, named in lower case as .NET names them: @code{utf-16be}, @code{iso-8859-1}, @code{windows-1252}, @code{shift_jis}, @code{koi8-r} and the rest. .NET's little-endian @code{utf-16} and @code{utf-32} are @code{utf-16le} and @code{utf-32le} here. @code{encoding-named} finds one by name and @code{encoding-of-code-page} by number, both as an @code{Option}. No encoding writes or skips a byte order mark. Each encoding is made the first time it is used, so importing the module costs nothing.
For more details, see @link["modules/text/encodings.html"]{@code{(text encodings)}}.