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: share> 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: share] BoxMap<k, v>

Builds an empty BoxMap.

Byte

Byte operations and byte classes.

type Byte = Byte

A primitive type representing a single byte.

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.

dec Byte.FromCode : [Nat] Byte

Converts a natural number to a byte modulo 256.

Bytes
type Bytes = Bytes

A primitive type representing a sequence of 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 either {
  .empty!,
  .ready iterative@attempt choice {
    .byte => Try<e, (Byte) self>,
    .close* => Try<e, !>,
    .minMax(Bytes.Pattern, Bytes.Pattern) => Try<e, either {
      .fail self@attempt,
      .match(Bytes, Bytes) self,
    }>,
    .minMaxEnd(Bytes.Pattern, Bytes.Pattern) => Try<e, either {
      .fail self@attempt,
      .match(Bytes, Bytes)!,
    }>,
    .remainder => Try<e, Bytes>,
  },
}

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

Cases:

  • .empty! — input is cleanly exhausted.
  • .ready parser — input is available, or the underlying source has failed. In the latter case, every parser operation returns .err.

Parser operations:

  • .close — close the parser.
  • .remainder — consume the parser and return all remaining bytes.
  • .byte — read the next byte.
  • .minMax(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, or .fail if no match (parser position unchanged).
  • .minMaxEnd(prefix, suffix) — like .minMax, 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* => Try<e, !>,
  .read => Try<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* => Try<e, !>,
  .flush => Try<e, self>,
  .write(Bytes) => Try<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.Chunks : [<e: drop> Bytes.Parser<e>] Stream<e, Bytes>

Streams a parser's remaining input one byte at a time. Closing the stream closes the parser and drops any resulting source error.

dec Bytes.Length : [Bytes] Nat

Returns the length of a byte sequence.

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

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

dec Bytes.PipeReader : [<e> [Bytes.Writer<!>] Try<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 Try<e, !> to propagate errors to the reader.

Bytes.PipeReader([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).

dec Bytes.Replace : [Bytes, Bytes, Bytes] Bytes

Replaces non-overlapping occurrences of a byte sequence with another byte sequence.

Bytes.Replace("red blue red", "red", "green")
// = "green blue green"

Replaces non-overlapping pattern matches using a replacement function.

Bytes.ReplacePattern("a12b345", .repeat1.one.range(<<48>>, <<57>>)!, box [_] "#")
// = "a#b#"
dec Bytes.SplitBy : [<e: drop> Bytes.Parser<e>, Bytes] Stream<e, Bytes>

Splits a parser's remaining input on a byte separator. Closing the stream closes the parser and drops any resulting source error.

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.

dec Char.FromCode : [Nat] Char

Converts a Unicode code point to a character. Invalid code points become the Unicode replacement character.

Data
Debug
dec Debug.Log : [String] !

Logs a string to stderr. Useful for debugging.

Float

Floating-point operations and constants.

type Float = Float

A primitive type representing a 64-bit floating point number.

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] Option<Float>

Parses a float literal or one of NaN, Inf, -Inf, Infinity, -Infinity. Returns .none! when the string is not valid.

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

A primitive type representing an arbitrary-precision integer.

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] Option<Int>

Parses a decimal string into an integer. Returns .none! 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 = 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.Error = String

Human-readable JSON parse/decode errors.

type Json.Format<a> = box choice {
  .parse(Json) => Try<!, 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.ObjectFormat<a> = box choice {
  .parseObject(BoxMap.Readonly<String, Json>) => Try<!, 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: drop> Json.ObjectFormat<a>, <b: drop> 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 safely discardable values because either side may need to be discarded if the other side fails.

dec Json.Empty : Json.ObjectFormat<!>

Parses an empty object. Ignores any fields, does not fail if fields are present.

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: drop> Json.Format<a>] Json.Format<List<a>>

Parses a JSON array with the given item format.

The item type must be safely discardable because earlier parsed items may need to be discarded if a later item fails to parse.

dec Json.Map : [<a> Json.Format<a>, <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 : [String, <a> 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("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>, <b> box [a] Try<!, 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 : [<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(*(
  (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(box [n] n * 2)
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!
type List.Builder<a> = iterative choice {
  .add(a) => self,
  .build* => List<a>,
}

Incrementally constructs a list.

dec List.All : [<a: drop> List<a>, box [a] Bool] Bool

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

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

Returns .true! if the test function 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: drop> List<a>, Nat] List<a>

Drops the requested number of elements from the start of a list.

dec List.DropWhile : [<a: share> List<a>, box [a] Bool] List<a>

Drops elements from the start while the test function returns .true!.

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

Keeps the elements for which the test function returns .true!.

dec List.FilterMap : [<a> List<a>, <b> box [a] Option<b>] List<b>

Maps each element to an optional value, keeping only the present results.

dec List.Find : [<a: share> List<a>, box [a] Bool] Option<a>

Returns the first element for which the test function returns .true!.

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

Maps each element to a list, then concatenates the result.

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

Applies a folding function 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: drop> List<a>] Nat

Returns the number of elements in a list.

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

Applies a mapping function to each element of a list.

*(1, 2, 3)->List.Map(box [n] n * 2)
// = *(2, 4, 6)
dec List.Max : [<a: data> List<a>] Option<a>

Returns the largest element, or .none! for an empty list.

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

Nondeterministically merges lists into a single list. The order of elements is determined by readiness. Items of a single list are yielded in order, but items from different lists may be interleaved depending on which list is ready to yield next.

This is an implementation of a fan-in pattern, where a single consumer receives items from multiple producers.

dec List.Min : [<a: data> List<a>] Option<a>

Returns the smallest element, or .none! for an empty list.

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

Returns a list with the elements in reverse order.

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: share> List<a>, <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: share> List<a>, <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>, <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>, <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: drop> List<a>, Nat] List<a>

Returns up to the requested number of elements from the start of a list.

dec List.TakeWhile : [<a: share> List<a>, box [a] Bool] List<a>

Takes elements from the start while the test function returns .true!.

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: drop> List<a>, <b: drop> 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: drop, <k: data> List<(k) 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

A primitive type representing an arbitrary-precision natural number.

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

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

dec Nat.FromString : [String] Option<Nat>

Parses a decimal string into a natural number. Returns .none! 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 either .some a or .none!.

  • .some a carries a value.
  • .none! means no value is available.
type Option<a> = either {
  .none!,
  .some a,
}

An optional value, either .some a or .none!.

dec Option.Filter : [<a: share> Option<a>, box [a] Bool] Option<a>

Keeps the contained value only if it satisfies the predicate.

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

Transforms the contained value with a computation that may return no value.

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

Transforms the contained value, if present.

dec Option.ToList : [<a> Option<a>] List<a>

Converts .some value to a singleton list and .none! to an empty list.

dec Option.ToTry : [<a> Option<a>, <e: drop> e] Try<e, a>

Converts .some value to .ok value and .none! to the provided error.

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

The result of a comparison between two values.

Stream

Finite pull-based streams with fallible production and infallible close.

Consumers request one item at a time with .next. A requested step can either produce an item, finish successfully, or finish with an error. Consumers may stop early with .close, allowing the producer to release its resources.

type Stream<e, a> = recursive choice {
  .close* => !,
  .next => either {
    .end Try<e, !>,
    .item(a) self,
  },
}

A finite pull-based sequence of values of type a whose production can fail with an error of type e.

Operations:

  • .close abandons the stream and releases its resources.
  • .next requests the next step. It returns .item(value) stream when an item is available, .end.ok! on normal completion, or .end.err e when production fails.
type Stream.Event<e, a> = either {
  .cancelled!,
  .ended Try<e, !>,
  .produced a,
  .spawned!,
}

A lifecycle or production event from a registered stream.

  • .spawned! — the stream was accepted.
  • .produced value — the stream produced a value.
  • .ended result — the stream ended normally or with an error.
  • .cancelled! — the registry closed the stream after cancellation.

Cancellation cannot interrupt an outstanding pull. It may therefore be preceded by one final .produced value, or natural .ended result may win instead.

type Stream.Events<id, e, a> = recursive either {
  .end!,
  .event(id, Stream.Event<e, a>) choice {
    .next* => self,
  },
}

A finite sequence of lifecycle and production events from a stream group.

Events from different streams are interleaved by readiness. For each ID, .spawned! comes first, produced values remain in stream order, and .ended result or .cancelled! terminates its lifecycle before that ID can be reused.

After each event, the consumer must select .next. This acknowledges event delivery, but streams are pulled eagerly: the first pull starts when a stream is spawned, and a subsequent pull may start before the current event is acknowledged. At most one pull is outstanding per stream.

Events may be dropped via auto-cleanup (if the items and errors are droppable), but keep in mind that dropping does not cancel the backing streams in a group or registry. The events will still be generated and consumed in the background.

type Stream.Group<e, a> = iterative choice {
  .cancelAll => self,
  .end => ?,
  .spawn(Stream<e, a>) => self,
}

Controls a dynamic group of concurrently pulled streams.

  • .spawn(stream) adds a stream.
  • .cancelAll requests cooperative cancellation of all currently active streams.
  • .end stops the controller without cancelling those already active.

When served by Group, streams receive consecutive Nat IDs starting at zero.

type Stream.Registry<id, e, a> = iterative choice {
  .alloc(id) => either {
    .free choice {
      .spawn(Stream<e, a>) => self,
    },
    .taken self,
  },
  .cancel(id) => (Bool) self,
  .cancelAll => self,
  .end => ?,
}

Controls a dynamic registry of concurrently pulled streams identified by id.

  • .alloc(id) — tries to reserves an ID for a stream, with two possible results:
    • .free — obliges the controller to provide its stream with .spawn, while
    • .taken — means the ID is already in use, and the stream cannot be spawned.
  • .cancel(id) — requests cooperative cancellation of the stream with the given ID and returns .true! when such stream is currently active. The ID remains taken until its stream cooperatively completes the cancellation.
  • .cancelAll — requests cooperative cancellation of all currently active streams.
  • .end — stops the controller without cancelling active streams.
dec Stream.All : [<e, a> Stream<e, a>, box [a] Bool] Try<e, Bool>

Returns .ok.true! if the test function holds for every item. Short-circuits and closes the source on the first .false!.

dec Stream.Any : [<e, a> Stream<e, a>, box [a] Bool] Try<e, Bool>

Returns .ok.true! if the test function holds for at least one item. Short-circuits and closes the source on the first .true!.

dec Stream.Collect : [<e, a> Stream<e, a>] (Try<e, !>) List<a>

Collects the stream into a list. If the stream fails, the items collected so far are returned along with the error.

dec Stream.Concat : [<e, a> List<Stream<e, a>>] Stream<e, a>

Concatenates a list of streams into a single stream.

dec Stream.Drop : [<e, a: drop> Stream<e, a>, Nat] Stream<e, a>

Skips the requested number of items and yields the rest.

dec Stream.DropWhile : [<e, a: share> Stream<e, a>, box [a] Bool] Stream<e, a>

Skips items while the test function returns .true!, then yields the rest.

dec Stream.Filter : [<e, a: share> Stream<e, a>, box [a] Bool] Stream<e, a>

Keeps the items for which the test function returns .true!.

dec Stream.FlatMap : [<e, a> Stream<e, a>, <b> box [a] Stream<e, b>] Stream<e, b>

Maps each item to a stream, then flattens the result.

dec Stream.ForEach : [<r> r, <e, a> Stream<e, a>, box [r, a] r] (Try<e, !>) r

Folds over the stream. The returned pair contains the stream completion status and the final accumulator.

dec Stream.FromList : [<a: drop> List<a>] Stream<either {}, a>

Creates an infallible stream from a list.

dec Stream.Group : [<e, a> dual Stream.Group<e, a>] Stream.Events<Nat, e, a>

Runs a stream group and returns its readiness-ordered events. The event sequence ends after the controller and all spawned streams have terminated.

let events = Stream.Group(chan group {
  group.spawn(firstStream)
  group.spawn(secondStream)
  group.end!
})
dec Stream.Map : [<e, a> Stream<e, a>, <b> box [a] b] Stream<e, b>

Applies a mapping function to each item of a stream.

dec Stream.MapErr : [<e1, a> Stream<e1, a>, <e2> box [e1] e2] Stream<e2, a>

Applies a mapping function to the stream's error type.

dec Stream.Registry : [<id: data, e, a> dual Stream.Registry<id, e, a>] Stream.Events<id, e, a>

Runs a keyed stream registry and returns its readiness-ordered events. The event sequence ends after the controller and all registered streams have terminated.

let events = Stream.Registry(chan registry {
  registry.alloc(id).case {
    .taken => {}
    .free => { registry.spawn(stream) }
  }
  registry.end!
})
dec Stream.Sum : [<e, a: number> Stream<e, a>] Try<e, a>

Calculates the sum of all stream items.

dec Stream.Take : [<e, a> Stream<e, a>, Nat] Stream<e, a>

Yields at most the requested number of items, closing the source when enough items have been taken.

dec Stream.TakeWhile : [<e, a: share> Stream<e, a>, box [a] Bool] Stream<e, a>

Yields items while the test function returns .true!, then closes the source.

dec Stream.ToList : [<e, a: drop> Stream<e, a>] Try<e, List<a>>

Collects the stream into a list. If the stream fails, the list is discarded and the error is returned.

String
type String = String

A primitive type representing a UTF-8 encoded 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 either {
  .empty!,
  .ready iterative@attempt choice {
    .char => Try<e, (Char) self>,
    .close* => Try<e, !>,
    .minMax(String.Pattern, String.Pattern) => Try<e, either {
      .fail self@attempt,
      .match(String, String) self,
    }>,
    .minMaxEnd(String.Pattern, String.Pattern) => Try<e, either {
      .fail self@attempt,
      .match(String, String)!,
    }>,
    .remainder => Try<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.

Cases:

  • .empty! — input is cleanly exhausted.
  • .ready parser — input is available, or the underlying source has failed. In the latter case, every parser operation returns .err.

Parser operations:

  • .close — close the parser, returning any source error.
  • .remainder — consume the parser and return all remaining unparsed input.
  • .char — read the next character.
  • .minMax(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, or .fail if no match (parser position unchanged).
  • .minMaxEnd(prefix, suffix) — like .minMax, 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.

String.Parse("Hello, world!").begin.case {
  .empty! => ...
  .ready r => r.minMax(.str "Hello", .str ", ").case {
    .err e => ...
    .ok .match(hello, comma) r => ...
    .ok .fail r => ...
  }
}
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: drop> String.Parser<e>] Stream<e, String>

Splits a parser's remaining input into lines separated by \n or \r\n. Closing the stream closes the parser and drops any resulting source error.

dec String.Parse : [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, \\).

dec String.ReadAll : [<e> Bytes.Reader<e>] Try<e, String>

Reads all bytes from a Reader and decodes them into a String, replacing invalid sequences with the Unicode replacement character.

dec String.Replace : [String, String, String] String

Replaces non-overlapping occurrences of a string with another string.

String.Replace("red blue red", "red", "green")
// = "green blue green"
dec String.SplitBy : [<e: drop> String.Parser<e>, String] Stream<e, String>

Splits a parser's remaining input on a string separator. Closing the stream closes the parser and drops any resulting source error.

dec String.Trim : [String] String

Trims whitespace from both ends of a string.

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.
Time

Instants, durations, time zones, and civil date-times.

An Instant is a point on the timeline; a Duration is a signed span of nanoseconds. The difference of two instants is a duration (Since), and two instants can be ordered (Compare). A Zone maps instants to UTC offsets, and InZone projects an instant into a Zoned civil date-time for calendar work.

type Time.Duration = Int

A signed span of time, measured in nanoseconds.

Duration is just Int, so it supports the full integer algebra: add and subtract durations, multiply or divide by a number, negate, and compare them. Build durations from the unit constants, e.g. 5 * Time.Second or 2 * Time.Hour + 30 * Time.Minute.

type Time.Instant = iterative box choice {
  .add(Time.Duration) => self,
  .unixNanos => Int,
}

A point on the timeline, independent of any time zone.

  • .unixNanos — nanoseconds since the Unix epoch (1970-01-01T00:00:00Z).
  • .add(duration) — shift the instant by a duration, returning a new instant.

Differences and ordering are the free functions Since and Compare; civil fields come from projecting into a Zone with InZone.

type Time.Weekday = either {
  .friday!,
  .monday!,
  .saturday!,
  .sunday!,
  .thursday!,
  .tuesday!,
  .wednesday!,
}

A day of the week.

type Time.Zone = box choice {
  .name => String,
  .offsetAt(Time.Instant) => Time.Duration,
}

A time zone: a mapping from instants to UTC offsets.

  • .name — the zone's name (an IANA name like "Europe/Prague", or an offset like "+02:00" for fixed zones).
  • .offsetAt(instant) — the zone's UTC offset at the given instant, as a duration (it can vary across the year because of daylight saving time).
type Time.Zoned = iterative box choice {
  .addDays(Int) => self,
  .addMonths(Int) => self,
  .addYears(Int) => self,
  .day => Nat,
  .format(String) => String,
  .hour => Nat,
  .instant => Time.Instant,
  .minute => Nat,
  .month => Nat,
  .nanosecond => Nat,
  .second => Nat,
  .weekday => Time.Weekday,
  .year => Int,
  .zone => Time.Zone,
}

An instant seen through a time zone: a civil date-time with calendar fields.

  • .year — the year (can be negative for years before 1 CE).
  • .month — the month, 1 to 12.
  • .day — the day of the month, 1 to 31.
  • .hour — the hour, 0 to 23.
  • .minute — the minute, 0 to 59.
  • .second — the second, 0 to 59.
  • .nanosecond — the sub-second part, 0 to 999999999.
  • .weekday — the day of the week.
  • .zone — the time zone this date-time is in.
  • .instant — the underlying instant on the timeline.
  • .format(layout) — render using a strftime-style layout.
  • .addYears(n) — shift by whole years on the calendar, returning a new value.
  • .addMonths(n) — shift by whole months on the calendar.
  • .addDays(n) — shift by whole days on the calendar.

Calendar arithmetic (.addYears / .addMonths / .addDays) respects the zone, including daylight-saving transitions. For exact arithmetic on the timeline use Instant.add instead.

dec Time.At : [Time.Zone, Int, Nat, Nat, Nat, Nat, Nat] Option<Time.Zoned>

Builds a civil date-time in a zone from its calendar fields: At(zone, year, month, day, hour, minute, second). Returns .none! if the fields do not denote a valid date and time.

dec Time.Now : Time.Instant

The current instant, read from the system clock.

Try

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

  • .ok a means a successful result.
  • .err e means an error has occurred.
type Try<e, a> = either {
  .err e,
  .ok a,
}

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

dec Try.Filter : [<e: drop, a: share> Try<e, a>, e, box [a] Bool] Try<e, a>

Keeps a successful value only if it satisfies the predicate, otherwise replaces it with the provided error.

dec Try.FlatMap : [<e, a> Try<e, a>, <b> box [a] Try<e, b>] Try<e, b>

Transforms the .ok value with a computation that may itself fail.

dec Try.Map : [<e, a> Try<e, a>, <b> box [a] b] Try<e, b>

Transforms the .ok value, if present.

dec Try.MapErr : [<e1, a> Try<e1, a>, <e2> box [e1] e2] Try<e2, a>

Transforms the .err value, if present.

dec Try.Ok : [<a> Try<either {}, a>] a

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

dec Try.ToList : [<e: drop, a> Try<e, a>] List<a>

Converts .ok value to a singleton list and .err _ to an empty list.

dec Try.ToOption : [<e: drop, a> Try<e, a>] Option<a>

Converts .ok value to .some value and .err _ to .none!.

Url

Parsed URLs and URL construction helpers.

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.
type Url.Error = String

Error type for URL parsing failures.