Types

fjs/types is the standard library's data layer: the values every other part of the repository is built from, and the functions over them. It is the most imported directory in the tree — the compiler, the effects layer, RTTI, the media formats and the website all reach for result, list, nullable and function before anything else.

Every module.f.* here is plain FunctionalScript. A value is never mutated, functions are curried with the configuration first and the data last, and nothing performs I/O. The one exception is result/module.mjs, a host JavaScript companion whose tryCatch and asyncTryCatch run a callback that may throw. Most calls take one argument each, but not all: fixpoint(step, same)(start) takes two in its first call. Most directories hold a module.f.mjs (or module.f.js), its types.ts, and a proof.f.mjs whose exported proof is the module's test suite.

Conventions

These hold across the directory, and knowing them makes every module below easier to read.

  • Absence is null. A lookup that finds nothing answers null, never undefined (nullable). A JavaScript API that answers undefined is converted at the boundary with fromUndefined.
  • Failure is a value. A step that can fail answers a Result: ['ok', value] or ['error', e]. Throwing is kept for broken invariants, not for input a caller could get wrong.
  • Sequences are lazy lists. A List may be an array, a null, a cons cell, a concatenation of two lists or a thunk, and every combinator accepts all five. Most combinators that answer a list, such as map or filter, do their work only when something reads the result. A few read the whole input when called, so they never return on an infinite list: those that answer a single value, such as fold and length, and reverse, which answers a list but has to reach the end first.
  • Functions take their configuration first. map(f)(list), at(key)(object), okThen(step)(result): the argument that varies least comes first, so a partially applied function is a reusable value.
  • Order is deterministic. Collections that a Map or an object would keep in insertion order (ordered_map, string_set, sorted_set) keep sorted order instead, so two equal collections built differently serialise the same way.

Where to start

If you need to…Read
return a value or an errorresult
handle a value that may be absentnullable
walk, transform or build a sequencelist
compose, flip or iterate functionsfunction
read an object's own property safelyobject
take apart a fixed or non-empty arrayarray
keep a sorted, persistent map or setbtree and its users
work with arbitrary-precision integers or bitsbigint, bit_vec

The modules

Core values

ModuleWhat it is
resultResult<T, E>: success or failure as a tagged tuple, with okThen, mapOk and okList.
nullableNullable<T> (T | null): match, map, fromUndefined, unwrap.
optionOption<T>, a value as a zero- or one-element tuple. Types only.
listList<T>, the lazy sequence, and about forty combinators over it.
functioncompose, identity, flip, iterate, fixpoint; operator, compare and length below it.
arrayReadonly arrays: safe at, first, last, splitFirst, splitLast, dedup, assoc.
objectPlain objects: own-property at, fromEntries, sort, isObject, structurallySame.
stringjoin, concat, repeat, cmp, splitAt and occurrences over strings and string lists.
numbersum, min, max, cmp, countOnes, isByte; is_negative_zero below it.
rangeA closed numeric interval [a, b] with contains and one.
versionDotted version numbers such as 26.1.0, parsed and compared by their numbers.

Type-level helpers

ModuleWhat it is
nominalBranded types that the type checker will neither mix nor order-compare with another.
phantomPhantom<S, T>, a type parameter with no runtime field, like Rust's PhantomData.
tsThe Equal compile-time check, used with Assert from asserts, and a printer that writes TypeScript type text.

Persistent collections

ModuleWhat it is
btreeThe persistent 2-3 B-tree that ordered_map and string_set are built on.
ordered_mapA string-keyed map, traversed in key order.
string_setA set of strings, traversed in order.
setA persistent set with Set's equality (objects by identity) and a logarithmic add.
mapmapSet and mapDelete: copy-on-write updates of a JavaScript Map.
sorted_listMerging, intersecting and searching sorted lists.
sorted_setA set held as a sorted array: union, intersect, has.
range_setA set of numbers as half-open boundaries, closed under union, intersection and complement.
range_mapA map from numeric ranges to values, with a merge for overlapping ranges.
bit_setThe bitmask-as-set algebra, shared by the two below.
byte_setA set of bytes (0..255) in one 256-bit bigint.
nibble_setA set of nibbles (0..15) in one 16-bit number.
patricia_trieA streaming Patricia trie that builds content-addressed binary trees.
stack_walkA driver for walking deep input on an explicit stack instead of the call stack.

Numbers and bits

ModuleWhat it is
bigintbigint utilities: log2, bitLength, abs, sign, factorial, divUp and more.
bigfloatDecimal-to-binary float conversion on bigint mantissas and exponents.
prime_fieldArithmetic modulo a prime: inverse, power and square root. The base of crypto/secp.
bit_vecBit vectors as bigints with a stop bit, and their conversions to and from bytes.
uint8arrayConversions between Uint8Array and bit vectors. Deprecated in favour of bit_vec.
  • fjs/rtti describes these same values at runtime: an RTTI schema can check that a parsed value really is a Result or a list of strings.
  • fjs/effects is the layer above: a value that performs operations, built from Result and List.
  • doc/DESIGN.md holds the principles these conventions come from.

Emergent Testing

Idle. Press Run to start the suite.

  • ./array/generate/proof.f.mjs
  • ./array/proof.f.mjs
  • ./array/repeat/proof.f.mjs
  • ./bigfloat/module.f.mjs
  • ./bigfloat/proof.f.mjs
  • ./bigint/demo.f.mjs
  • ./bigint/from_number/proof.f.mjs
  • ./bigint/proof.f.mjs
  • ./bit_set/proof.f.mjs
  • ./bit_vec/proof.f.mjs
  • ./btree/find/proof.f.mjs
  • ./btree/proof.f.mjs
  • ./btree/remove/module.f.js
  • ./btree/remove/proof.f.mjs
  • ./btree/set/proof.f.mjs
  • ./btree/types/proof.f.mjs
  • ./byte_set/proof.f.mjs
  • ./function/compare/proof.f.mjs
  • ./function/length/proof.f.mjs
  • ./function/operator/proof.f.mjs
  • ./function/proof.f.mjs
  • ./list/alt/proof.f.mjs
  • ./list/iterable/proof.f.mjs
  • ./list/proof.f.mjs
  • ./map/proof.f.mjs
  • ./nibble_set/proof.f.mjs
  • ./nominal/proof.f.mjs
  • ./nullable/proof.f.mjs
  • ./number/abs/proof.f.mjs
  • ./number/ceil/proof.f.mjs
  • ./number/is_negative_zero/proof.f.mjs
  • ./number/max/proof.f.mjs
  • ./number/min/proof.f.mjs
  • ./number/proof.f.mjs
  • ./object/entry/proof.f.mjs
  • ./object/proof.f.mjs
  • ./object/structurally_same/proof.f.mjs
  • ./ordered_map/proof.f.mjs
  • ./patricia_trie/proof.f.mjs
  • ./prime_field/proof.f.mjs
  • ./range/proof.f.mjs
  • ./range_map/proof.f.mjs
  • ./range_set/proof.f.mjs
  • ./result/proof.f.mjs
  • ./set/proof.f.mjs
  • ./sorted_list/proof.f.mjs
  • ./sorted_set/proof.f.mjs
  • ./stack_walk/proof.f.mjs
  • ./string/proof.f.mjs
  • ./string_set/proof.f.mjs
  • ./ts/proof.f.mjs
  • ./uint8array/proof.f.mjs
  • ./version/proof.f.mjs