BjoManual/_03.Standard-library.sz

119 lines
15 KiB
Text
Raw Normal View History

@section{The standard library}
2026-10-01 11:36:18 +02:00
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)}}.
2026-10-01 11:36:18 +02:00
@subsection{std/maths}
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)}}.
2026-10-01 11:36:18 +02:00
@subsection{std/fmt}
Formatting in Bjolang is divided into two layers: interpolation and layout.
Interpolation provides a simple way to combine mixed scalar types into strings or print them directly using @code{println*} and @code{str*}.
The layout layer provides a composable block algebra for more complex text formatting, such as padding, aligning, wrapping paragraphs, and laying out tables.
For more details, see @link["modules/std/fmt.html"]{@code{(std fmt)}}.
2026-10-01 11:36:18 +02:00
@subsection{std/rx}
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 ...)}).
For more details, see @link["modules/std/rx.html"]{@code{(std rx)}}.
2026-10-01 11:36:18 +02:00
@subsection{std/http}
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}.
For more details, see @link["modules/std/http.html"]{@code{(std http)}}.
2026-10-01 11:36:18 +02:00
@subsection{std/run}
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.
For more details, see @link["modules/std/run.html"]{@code{(std run)}}.
2026-10-01 11:36:18 +02:00
@subsection{std/random}
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.
For more details, see @link["modules/std/random.html"]{@code{(std random)}}.
2026-10-01 11:36:18 +02:00
@subsection{std/atomic}
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)}}.
@subsection{std/stm}
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)}}.
2026-10-01 11:36:18 +02:00
@subsection{std/datetime}
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.
For more details, see @link["modules/std/datetime.html"]{@code{(std datetime)}}.
2026-10-01 11:36:18 +02:00
@subsection{std/eq and std/clr-ord}
@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)}}.
@subsection{std/mutable}
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)}}.
@subsection{std/stopwatch}
Stopwatches that read the ambient clock, so a test can bind a clock and get an exact time. @code{time-it} runs a body a number of times and reports the time and memory that it used.
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)}}.
2026-10-01 11:36:18 +02:00
@subsection{text/bjodat}
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.
For more details, see @link["modules/text/bjodat.html"]{@code{(text bjodat)}}.
2026-10-01 11:36:18 +02:00
@subsection{text/json}
The @code{text/json} module provides JSON parsing and generation capabilities. Like @code{bjodat}, it allows for working with structured data but using the standard JSON format, which is essential for web communication.
For more details, see @code{prelude.org} and related standard library documentation.