Package core

Built-in package

Modules

Bench

Benchmarking helpers.

dec Bench.BlackBox : [type a, a] a

Identity function intended for benchmarks.

Bool
type Bool = either {
  .false !,
  .true !,
}

A boolean value.

BoxMap

Non-linear ordered-map interface with data keys and non-linear values.

type BoxMap<k, v> = iterative box choice {
  .delete => [k] self,
  .get => [k] Option<v>,
  .keys => List<k>,
  .list => List<(k) v>,
  .put => [k, v] self,
  .size => Nat,
}

A non-linear ordered map interface.

  • .size — get the number of entries.
  • .keys — get the keys in map order.
  • .list — get all entries as (key) value pairs.
  • .get(key) — look up a key.
  • .put(key, value) — return a map with that entry inserted or updated.
  • .delete(key) — return a map with that entry removed.

Since BoxMap is non-linear, updates return another BoxMap value.

type BoxMap.Readonly<k, v> = box choice {
  .get => [k] Option<v>,
  .keys => List<k>,
  .list => List<(k) v>,
  .size => Nat,
}

A read-only view of a BoxMap.

dec BoxMap.FromList : <k: data, v: box>[List<(k) v>] BoxMap<k, v>

Builds a BoxMap from (key) value pairs. If a key appears more than once, the last pair wins.

dec BoxMap.New : [type k: data, type v: box] BoxMap<k, v>

Builds an empty BoxMap.

Byte

Byte operations and byte classes.

type Byte.Class = either {
  .any !,
  .byte Byte,
  .range (Byte, Byte)!,
}

A class of bytes for parsers and Byte.Is.

  • .any! — any byte.
  • .byte b — a specific byte.
  • .range(lo, hi)! — bytes in the inclusive range [lo, hi].
dec Byte.Code : [Byte] Nat

Returns the numeric value of a byte (0-255) as a natural number.

Bytes
type Bytes.Builder = iterative choice {
  .add => [Bytes] self,
  .build => Bytes,
}

An incremental byte buffer builder. Add chunks with .add, then finalize with .build.

type Bytes.Parser<e> = recursive iterative@attempt choice {
  .byte => either {
    .byte (Byte) self,
    .end Result<e, !>,
  },
  .close => Result<e, !>,
  .match => [Bytes.Pattern, Bytes.Pattern] either {
    .end Result<e, !>,
    .fail self@attempt,
    .match (Bytes, Bytes) self,
  },
  .matchEnd => [Bytes.Pattern, Bytes.Pattern] either {
    .end Result<e, !>,
    .fail self@attempt,
    .match (Bytes, Bytes)!,
  },
  .remainder => Result<e, Bytes>,
}

A streaming byte parser, parameterized by an error type e. Works like String.Parser but operates on raw bytes.

Operations:

  • .close — close the parser.
  • .remainder — consume the parser and return all remaining bytes.
  • .byte — read the next byte. Returns .end or .byte(b).
  • .match(prefix, suffix) — find the leftmost split where prefix matches the left part and suffix matches the longest possible right part. Returns .match(prefix_bytes, suffix_bytes) on success, .fail if no match (parser position unchanged), or .end if input is empty.
  • .matchEnd(prefix, suffix) — like .match, but the suffix extends to the end of input. Terminates the parser on success.

Use .begin/.loop (from the recursive wrapper) to iterate over multiple matches.

type Bytes.Pattern = recursive either {
  .and List<self>,
  .bytes Bytes,
  .concat List<self>,
  .empty !,
  .max Nat,
  .min Nat,
  .non Byte.Class,
  .one Byte.Class,
  .or List<self>,
  .repeat self,
  .repeat1 self,
}

A pattern for matching within byte sequences.

Atomic patterns:

  • .empty! — matches empty bytes.
  • .bytes b — matches literal bytes.
  • .one class — matches a single byte of the given Byte.Class.
  • .non class — matches a single byte NOT in the given Byte.Class.
  • .min n — matches at least n bytes (any).
  • .max n — matches at most n bytes (any).

Combinators:

  • .repeat p — matches zero or more repetitions of pattern p.
  • .repeat1 p — matches one or more repetitions of pattern p.
  • .concat ps — matches a sequence of patterns in order.
  • .and ps — matches only if all patterns match the same input.
  • .or ps — matches if any of the patterns match.
type Bytes.Reader<e> = recursive choice {
  .close => Result<e, !>,
  .read => Result<e, either {
    .chunk (Bytes) self,
    .end !,
  }>,
}

A streaming byte reader, parameterized by an error type e.

  • .close — close the reader and return any error.
  • .read — read the next chunk. Returns .end when exhausted, or .chunk(bytes) with the next chunk of data.
type Bytes.Writer<e> = iterative choice {
  .close => Result<e, !>,
  .flush => Result<e, self>,
  .write => [Bytes] Result<e, self>,
}

A streaming byte writer, parameterized by an error type e.

  • .close — close the writer, flushing any pending data.
  • .flush — flush pending data without closing.
  • .write(bytes) — write a chunk of bytes.
dec Bytes.Length : [Bytes] Nat

Returns the length of a byte sequence.

dec Bytes.Parser : [Bytes] Bytes.Parser<either {}>

Creates a byte Parser from a byte sequence. The error type is either {} (impossible).

dec Bytes.PipeReader : [type e, [Bytes.Writer<!>] Result<e, !>] Bytes.Reader<e>

Creates a Reader from a function that writes to a Writer. The function receives a Writer<!> whose writes fail with ! if the reader's consumer closes early, signaling the writer to stop. The function returns Result<e, !> to propagate errors to the reader.

Bytes.PipeReader(type MyError, [w]
  catch ! => .ok! in
  do {
    w.write("hello").try
    w.close.try
  } in .ok!
)
dec Bytes.Reader : [Bytes] Bytes.Reader<either {}>

Creates a Reader from a byte sequence. The error type is either {} (impossible).

Cell

Shared cells.

type Cell<a> = iterative choice {
  .end => ?,
  .split => [dual self] self,
  .take => (a) choice {
    .put => [a] self,
  },
}

A shared cell containing a value.

  • .end — release the cell.
  • .split — create another handle to the same cell.
  • .take — remove the current value and continue by choosing .put.
dec Cell.Share : <a>[a] [dual Cell<a>] a

Serves a value through a Cell. Returns the final value when all clients are done.

Char

Character operations and character classes.

type Char.Class = either {
  .any !,
  .ascii either {
    .alpha !,
    .alphanum !,
    .any !,
    .digit !,
  },
  .char Char,
  .whitespace !,
}

A class of characters for parsers and Char.Is.

  • .any! — any character.
  • .char c — a specific character.
  • .whitespace! — any whitespace character.
  • .ascii.any! — any ASCII character.
  • .ascii.alpha! — ASCII letter (a-z, A-Z).
  • .ascii.alphanum! — ASCII letter or digit.
  • .ascii.digit! — ASCII digit (0-9).
dec Char.Code : [Char] Nat

Returns the Unicode code point of a character as a natural number.

Data
Debug
dec Debug.Log : [String] !

Logs a string to stderr. Useful for debugging.

Float

Floating-point operations and constants.

dec Float.Atan2 : [Float, Float] Float

Float.Atan2(y, x) is the two-argument arctangent of (y, x).

dec Float.E : Float

Euler's number.

dec Float.Equals : [Float, Float, Float] Bool

Float.Equals(left, right, tolerance) tests whether left and right differ by at most tolerance. Returns .false! if any argument is NaN.

dec Float.FromString : [String] either {
  .err !,
  .ok Float,
}

Parses a float literal or one of NaN, Inf, -Inf, Infinity, -Infinity.

dec Float.Inf : Float

Positive infinity.

dec Float.Max : [Float, Float] Float

Returns the larger input, or NaN if either input is NaN.

dec Float.Min : [Float, Float] Float

Returns the smaller input, or NaN if either input is NaN.

dec Float.NaN : Float

The IEEE-754 "not a number" value.

dec Float.Pi : Float

Archimedes' constant.

dec Float.Pow : [Float, Float] Float

Float.Pow(base, exponent) returns base raised to the power exponent.

dec Float.Round : [Float] Float

Rounds to the nearest integer, ties away from zero.

dec Float.ToInt : [Float] Int

Truncates a float toward zero. Returns 0 for NaN, Inf, and NegInf.

Int

Integer operations.

type Int = Int
dec Int.Abs : [Int] Nat

Returns the absolute value of an integer as a natural number.

dec Int.Clamp : [Int, Int, Int] Int

Int.Clamp(x)(lo, hi) clamps x to the inclusive range [lo, hi].

Int.Clamp(7)(0, 5)   // = 5
Int.Clamp(-3)(0, 5)  // = 0
dec Int.FromString : [String] either {
  .err !,
  .ok Int,
}

Parses a decimal string into an integer. Returns .err! when the string is not a valid integer.

dec Int.Max : [Int, Int] Int

Returns the larger of two integers.

dec Int.Min : [Int, Int] Int

Returns the smaller of two integers.

dec Int.Mod : [Int, Nat] Nat

Int.Mod(x, n) returns the non-negative remainder of x modulo n. The result is in [0, n), or 0 when n is 0.

dec Int.Range : [Int, Int] List<Int>

Int.Range(lo, hi) produces the integers from lo (inclusive) to hi (exclusive).

Int.Range(0, 5)  // = *(0, 1, 2, 3, 4)
Json

JSON encoding/decoding.

type Json.Error = String

Human-readable JSON parse/decode errors.

type Json.Format<a> = box choice {
  .parse => [Json] Option<a>,
}

A reusable parser from a materialized Json value into a typed value.

A Format<a> exposes a single .parse operation that returns .ok value on success or .err! on mismatch.

type Json = recursive either {
  .bool Bool,
  .list List<self>,
  .null !,
  .number Float,
  .object BoxMap.Readonly<String, self>,
  .string String,
}

A materialized JSON value.

Notes:

  • .number uses Float.
  • Encoding .number(Float.NaN), .number(Float.Inf), or .number(Float.NegInf) produces JSON null.
  • Object keys are normalized through BoxMap.Readonly, so duplicate source keys and original key order are not preserved.
type Json.ObjectFormat<a> = box choice {
  .parseObject => [BoxMap.Readonly<String, Json>] Option<a>,
}

A reusable parser specialized to JSON objects.

Use Json.Object(...) to lift an ObjectFormat<a> into a full Format<a>.

dec Json.And : <a: box>[Json.ObjectFormat<a>] <b: box>[Json.ObjectFormat<b>] Json.ObjectFormat<(b) a>

Runs two object formats against the same object and returns both results.

The result shape is (right) left, so Json.Field("age", Json.Number)->Json.And(Json.Field("name", Json.String)) returns (String) Float.

Both object formats return non-linear values because either side may need to be discarded if the other side fails.

dec Json.Equals : [Json, Json] Bool

Tests two Json values for structural equality.

Object key order does not matter, because objects are normalized through BoxMap.Readonly.

dec Json.Field : [String] <a>[Json.Format<a>] Json.ObjectFormat<a>

Parses a required object field with the given format.

For example, Json.Field("name", Json.String) accepts an object whose "name" field is a JSON string.

dec Json.List : <a: box>[Json.Format<a>] Json.Format<List<a>>

Parses a JSON array with the given item format.

The item type must be non-linear because earlier parsed items may need to be discarded if a later item fails to parse.

dec Json.Map : <a>[Json.Format<a>] [type b, box [a] b] Json.Format<b>

Applies a pure mapping function to a successful parse result.

Use Json.Map when parsing cannot fail once the underlying format succeeds. Use Json.Then for fallible post-processing.

dec Json.Tagged : [type a, String, List<(Json) <b>(Json.ObjectFormat<b>) box [b] a>] Json.Format<a>

Parses tagged JSON objects by matching one field against literal JSON tags.

The first argument selects the field to inspect. Each branch provides a tag literal, an object format, and a mapper into the result type. Tags are compared with Json.Equals, so they may be strings, numbers, booleans, or null, not just strings.

type Command = either {
  .sleep Float,
  .say String,
}

def CommandFormat = Json.Tagged(type Command, "operation", *(
  (.string "sleep", Json.Field("seconds", Json.Number)) box [seconds] .sleep seconds,
  (.string "say", Json.Field("message", Json.String)) box [message] .say message,
))
dec Json.Then : <a>[Json.Format<a>] [type b, box [a] Option<b>] Json.Format<b>

Applies a fallible post-processing step to a successful parse result.

The mapping function returns .ok value to accept the parsed result or .err! to reject it.

dec Json.Union : [type a, List<<b>(Json.Format<b>) box [b] a>] Json.Format<a>

Tries multiple formats in order and returns the first successful result.

Each branch may parse to its own intermediate type before mapping into the shared result type.

type Answer = either {
  .yes!,
  .text String,
}

def AnswerFormat = Json.Union(type Answer, *(
  (Json.Literal(.string "yes")) box [!] .yes!,
  (Json.String) box [text] .text text,
))
List

Finite list types and list combinators.

let xs = *(1, 2, 3)
xs->List.Map(type Int, box [n] n * 2)
type List.Builder<a> = iterative choice {
  .add => [a] self,
  .build => List<a>,
}

Incrementally constructs a list.

type List.Fallible<e, a> = recursive either {
  .end Result<e, !>,
  .item (a) self,
}

A list that ends with Result<e, !> instead of !. Use it for streams that may finish with an error.

type List<a> = recursive either {
  .end !,
  .item (a) self,
}

A finite, ordered sequence of values.

*(1, 2, 3)  // syntax sugar for .item(1) .item(2) .item(3) .end!
dec List.All : <a: box>[List<a>] [box [a] Bool] Bool

Returns .true! if the predicate holds for all elements. Short-circuits on the first .false!.

dec List.Any : <a: box>[List<a>] [box [a] Bool] Bool

Returns .true! if the predicate holds for at least one element. Short-circuits on the first .true!.

dec List.Concat : <a>[List<List<a>>] List<a>

Flattens a list of lists into a single list.

dec List.Copy : <a>[dual List<a>] [List<a>] dual List<a>

Yields all items from a source list onto a destination channel, consuming the source.

dec List.Drop : <a: box>[List<a>] [Nat] List<a>

Drops the first n elements of a list and returns the rest.

dec List.Filter : <a: box>[List<a>] [box [a] Bool] List<a>

Keeps the elements for which the predicate returns .true!.

dec List.FlatMap : <a>[List<a>] [type b, box [a] List<b>] List<b>

Applies f to each element and concatenates the resulting lists.

dec List.ForEach : <r>[r] <a>[List<a>] [box [r, a] r] r

Applies f repeatedly to the current result and each list element, returning the final result.

Expression syntax:

{0}->List.ForEach(*(1, 2, 3), box [sum, n] sum + n)
// = 6

Process syntax:

let console = Console.Open
console->List.ForEach(Nat.Range(1, 10), box [c, i]
  c.print(`#{i}`)
)
console.close
dec List.Length : <a: box>[List<a>] Nat

Returns the number of elements in a list.

dec List.Map : <a>[List<a>] [type b, box [a] b] List<b>

Applies f to each element of a list.

{*(1, 2, 3)}->List.Map(type Int, box [n] n * 2)
// = *(2, 4, 6)
dec List.Sort : <a: data>[List<a>] List<a>

Sorts a list in ascending data order. Equal keys keep their original order.

dec List.SortBy : <a: box>[List<a>] [type k: data, box [a] k] List<a>

Sorts a non-linear list by an extracted data key.

dec List.SortDesc : <a: data>[List<a>] List<a>

Sorts a list in descending data order. Equal keys keep their original order.

dec List.SortDescBy : <a: box>[List<a>] [type k: data, box [a] k] List<a>

Sorts a non-linear list by an extracted data key in descending order.

dec List.SortLinearBy : <a>[List<a>] [type k: data, box [a] (k) a] List<a>

Sorts a linear list by a function that returns both the key and the item.

dec List.SortLinearDescBy : <a>[List<a>] [type k: data, box [a] (k) a] List<a>

Sorts a linear list by a key in descending order.

dec List.Sum : <a: number>[List<a>] a

Calculates the sum of all elements in a list.

dec List.Take : <a: box>[List<a>] [Nat] List<a>

Returns the first n elements of a list.

dec List.Unzip : <a, b>[List<(a) b>] (List<a>) List<b>

Splits a list of pairs into a pair of lists.

dec List.Zip : <a: box>[List<a>] <b: box>[List<b>] List<(a) b>

Zips two lists into a list of pairs. Stops at the shorter list.

Map

Linear ordered-map interface with data keys.

type Map<k, v> = iterative choice {
  .entry => [k] (Option<v>) choice {
    .delete => self,
    .put => [v] self,
  },
  .keys => (List<k>) self,
  .list => List<(k) v>,
  .size => (Nat) self,
}

A linear ordered map interface.

  • .size — get the number of entries while keeping the map.
  • .keys — get the keys in map order while keeping the map.
  • .list — consume the map and return its entries as (key) value pairs.
  • .entry(key) — inspect the current Option<v> for key, then choose .put(value) or .delete.

The map is linear: .list consumes it, while .size, .keys, and .entry return a continuation for further use.

dec Map.FromList : [type v] <k: data>[List<(k) box v>] Map<k, v>

Builds a Map from (key) value pairs. If a key appears more than once, the last pair wins.

dec Map.New : [type k: data, type v] Map<k, v>

Builds an empty Map.

Nat

Natural-number operations and iterators.

type Nat = Nat
dec Nat.Clamp : [Int, Nat, Nat] Nat

Nat.Clamp(x)(lo, hi) clamps x to the inclusive range [lo, hi].

dec Nat.FromString : [String] either {
  .err !,
  .ok Nat,
}

Parses a decimal string into a natural number. Returns .err! when the string is not a valid non-negative integer.

dec Nat.Max : [Nat, Int] Nat

Nat.Max(n, m) returns the larger of n and m. The result is always a Nat, even though m is an Int.

dec Nat.Min : [Nat, Nat] Nat

Returns the smaller of two natural numbers.

dec Nat.Mod : [Nat, Nat] Nat

Nat.Mod(m, n) is the remainder of dividing m by n. Returns 0 when n is 0.

dec Nat.Range : [Nat, Nat] List<Nat>

Nat.Range(lo, hi) produces the naturals from lo (inclusive) to hi (exclusive).

Nat.Range(0, 4)  // = *(0, 1, 2, 3)
dec Nat.Repeat : [Nat] recursive either {
  .end !,
  .step self,
}

Produces n repetitions of .step, followed by .end!.

Nat.Repeat(3).begin.case {
  .end! => "done",
  .step next => ... next.loop,
}
dec Nat.RepeatLazy : [Nat] recursive either {
  .end !,
  .step box choice {
    .next => self,
  },
}

Like Repeat, but each .step carries a boxed continuation behind .next. Use it when later steps might not be needed.

Number
dec Number.Add : <a: number>[(a) a] a
dec Number.Div : <a: number>[(a) a] a
dec Number.Mul : <a: number>[(a) a] a
dec Number.Neg : <a: signed>[a] a
dec Number.Sub : <a: signed>[(a) a] a
dec Number.Zero : [type a: number] a
Option

Option<a> is Result<!, a>.

  • .ok value carries a value.
  • .err! means no value is available.
type Option<a> = Result<!, a>

An optional value, defined as Result<!, a>.

Ordering
type Ordering = either {
  .equal !,
  .greater !,
  .less !,
}

The result of a comparison between two values.

Result

Result<e, a> carries either .ok a or .err e.

let try value = Result.Always(value)
type Result<e, a> = either {
  .err e,
  .ok a,
}

A value that is either .ok a or .err e.

dec Result.Always : <a>[Result<either {}, a>] a

Extracts the .ok branch from a Result<either {}, a>.

String
type String.Builder = iterative choice {
  .add => [String] self,
  .build => String,
}

An incremental string builder. Add strings with .add, then finalize with .build.

String.Builder.add("Hello").add(", ").add("world!").build
// = "Hello, world!"
type String.Parser<e> = recursive iterative@attempt choice {
  .char => either {
    .char (Char) self,
    .end Result<e, !>,
  },
  .close => Result<e, !>,
  .match => [String.Pattern, String.Pattern] either {
    .end Result<e, !>,
    .fail self@attempt,
    .match (String, String) self,
  },
  .matchEnd => [String.Pattern, String.Pattern] either {
    .end Result<e, !>,
    .fail self@attempt,
    .match (String, String)!,
  },
  .remainder => Result<e, String>,
}

A streaming string parser, parameterized by an error type e.

The error type comes from the underlying source: either {} (impossible) when parsing a plain string, or the reader's error type when parsing from a Bytes.Reader.

Operations:

  • .close — close the parser, returning any source error.
  • .remainder — consume the parser and return all remaining unparsed input.
  • .char — read the next character. Returns .end if input is exhausted, or .char(c) with the character.
  • .match(prefix, suffix) — find the leftmost split where prefix matches the left part and suffix matches the longest possible right part. Returns .match(prefix_str, suffix_str) on success, .fail if no match (parser position unchanged), or .end if input is empty.
  • .matchEnd(prefix, suffix) — like .match, but the suffix extends to the end of input. Terminates the parser on success.

Use .begin/.loop (from the recursive wrapper) to iterate over multiple matches.

let r = String.Parser("Hello, world!")
r.match(.str "Hello", .str ", ").case {
  .match(hello, comma) r => ...
  .fail r => ...
  .end _ => ...
}
type String.Pattern = recursive either {
  .and List<self>,
  .concat List<self>,
  .empty !,
  .max Nat,
  .min Nat,
  .non Char.Class,
  .one Char.Class,
  .or List<self>,
  .repeat self,
  .repeat1 self,
  .str String,
}

A pattern for matching within strings.

Atomic patterns:

  • .empty! — matches the empty string.
  • .str s — matches a literal string.
  • .one class — matches a single character of the given Char.Class.
  • .non class — matches a single character NOT in the given Char.Class.
  • .min n — matches at least n characters (any).
  • .max n — matches at most n characters (any).

Combinators:

  • .repeat p — matches zero or more repetitions of pattern p.
  • .repeat1 p — matches one or more repetitions of pattern p.
  • .concat ps — matches a sequence of patterns in order.
  • .and ps — matches only if all patterns match the same input.
  • .or ps — matches if any of the patterns match.

Common idiom: .repeat.one.any! matches any number of any characters.

dec String.Concat : [List<String>] String

Concatenates a list of strings into a single string.

String.Concat(*("Hello", ", ", "world!"))  // = "Hello, world!"
dec String.FromBytes : [Bytes] String

Decodes bytes as UTF-8 into a string, replacing invalid sequences with the Unicode replacement character.

dec String.Join : [List<String>, String] String

Joins a list of strings with a separator between each element.

String.Join(*("a", "b", "c"), ", ")  // = "a, b, c"
dec String.Lines : <e>[String.Parser<e>] List.Fallible<e, String>

Splits a parser's remaining input into lines (separated by \n). Returns a fallible list that may end with a source error.

dec String.Parser : [String] String.Parser<either {}>

Creates a Parser from a string. The error type is either {} (impossible).

dec String.Quote : [String] String

Wraps a string in quotes with escape sequences (e.g. \n, \t, \\).

Test
type Test = iterative box choice {
  .assert => [String, Bool] self,
  .done => !,
  .id => ([type a, a] a) self,
  .leak => ([type a, a] !) self,
}

A test runner interface for writing tests.

  • .assert — check a condition with a label.
  • .done — finish the test.
  • .id — obtain the identity function (useful for testing type-generic code).
  • .leak — obtain a function that discards any value.
Url

Parsed URLs and URL construction helpers.

type Url.Error = String

Error type for URL parsing failures.

type Url = iterative box choice {
  .addQuery => [String, String] self,
  .appendPath => [String] self,
  .full => String,
  .host => String,
  .path => String,
  .protocol => String,
  .query => List<(String) String>,
}

A URL value with inspection operations and derived updates.

  • .full — get the full URL string.
  • .protocol — get the scheme (e.g. "http", "https").
  • .host — get the host, including port if present.
  • .path — get the decoded path.
  • .query — get the query parameters as a list of (key) value pairs.
  • .appendPath(segment) — append a path segment.
  • .addQuery(key, value) — add a query parameter. .appendPath and .addQuery return updated Url values.