Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

The Prelude

The always-on prelude: wired-in types, the type-class tower, core combinators, and the effect/loop machinery.

The broad data-structure surface (lists, maybe/result, maps, sets, strings, chars) lives in importable stdlib modules under Data.*; the glob imports below re-open them into unqualified scope so every name stays available without an explicit import.

Types

Option

type Option(a) = None | Some(a) deriving (Eq, Show)

The optional type: None, or Some(a) holding a value.

Result

type Result(a, e) = Ok(a) | Err(e) deriving (Eq, Show)

A computation outcome: Ok(a) on success or Err(e) on failure.

List

type List(a) = Nil | Cons(a, List(a)) deriving (Eq)

A singly-linked list: Nil, or Cons(head, tail). Backs [..] literals.

Map

type Map(k, v, ord) = Tip | Bin(Int, k, v, Map(k, v, ord), Map(k, v, ord))

A persistent ordered map, an AVL tree (Tip/Bin); see Data.Map. The third parameter ord is a phantom brand recording the ordering witness the map was built under; it never appears in a field, so an unbranded Map(k, v) is the same type under-applied (a fresh brand per use). See Data.Map.

Canonical

type Canonical = MkCanonical

The brand of a map built under the ambient canonical ordering, when no explicit ordering witness is in scope. A map built inside with w <- ordering carries w’s private brand instead, so a value of one brand never unifies with the other. Maps stored in a container that pins a concrete brand (rather than staying brand-polymorphic) use this one.

HashMap

type HashMap(v) = HM { buckets: Array(List((String, v))), size: Int }

A separate-chaining hash table with String keys, built on the growable Array: each bucket is an association list, and the table doubles its bucket count when the load factor passes 1. Iteration order is a pure function of the inserts, identical across the interpreter and native backends.

Type Classes

Eq

class Eq(a)
  eq : (a, a) -> Bool

Equality. eq backs ==//=.

Ord

class Ord(a) given Eq(a)
  cmp : (a, a) -> Int

Total order. cmp(x, y) returns -1, 0, or 1; backs </<=/>/>=.

Show

class Show(a)
  show : (a) -> String

Canonical rendering to a String, dispatched by dictionary. show(x) reads x’s Show instance, so a value prints canonically even in a polymorphic context (where the runtime representation alone cannot tell, say, a Bool from an Int). Derive it with deriving (Show); strings render quoted and escaped, records with their field names.

Hash

class Hash(a)
  hash : (a) -> String

A content hash of a value, as a lowercase blake3 hex digest. deriving (Hash) folds a value structurally into the same content-addressing scheme the compiler hashes code with (a constructor token followed by its fields’ own digests), so structurally equal values hash equal, byte-for-byte identically on the interpreter and native backends. The leaf instances below anchor the fold.

Pow

class Pow(a)
  pow : (a, a) -> a

Exponentiation, the class a ^ b desugars to. Int and Float instances cover homogeneous powers; a mixed Int ^ Float is a type error.

Num

class Num(a)
  plus : (a, a) -> a
  minus : (a, a) -> a
  times : (a, a) -> a
  negated : (a) -> a
  from_int : (Int) -> a

The additive-multiplicative core of the numerical tower: +, -, *, and unary minus (negated) over one lane. A monomorphic operand keeps its direct lane primitive (the dictionary never survives specialization); a given Num(a) operand dispatches here. Div is split off so a type with addition but no sensible division stays representable. No implicit coercion: an operand’s lane is fixed by its type, and only literals adapt to context.

Div

class Div(a)
  quotient : (a, a) -> a
  modulo : (a, a) -> a

Division and remainder, the / and % operators. Integer lanes truncate toward zero with the remainder taking the dividend’s sign and fault on a zero divisor; Float division is IEEE (never faults) and % is fmod.

Functor

class Functor(f)
  fmap : ((a) -> b ! {| e}, f(a)) -> f(b) ! {| e}

A container that can be mapped over. fmap is effect-polymorphic, so mapping an effectful function threads its row e through.

Foldable

class Foldable(t)
  fold_r : ((a, b) -> b ! {| e}, b, t(a)) -> b ! {| e}
  fold_l : ((b, a) -> b ! {| e}, b, t(a)) -> b ! {| e}

A container collapsible with an effect-polymorphic fold from either end. fold_l must be tail recursive in every instance: the aggregations in Data.Foldable ride it, so a million-element container folds in constant stack on the native backend.

Applicative

class Applicative(f) given Functor(f)
  pure : (a) -> f(a)
  ap : (f((a) -> b ! {| e}), f(a)) -> f(b) ! {| e}

A Functor with pure (inject a value) and ap (apply a wrapped function).

Monad

class Monad(m) given Applicative(m)
  bind : (m(a), (a) -> m(b) ! {| e}) -> m(b) ! {| e}

Structural sequencing via bind. Side effects ride the effect system, so this is for List/Option-style structure rather than do-notation.

Traversable

class Traversable(t) given Functor(t), Foldable(t)
  traverse : ((a) -> b ! {| e}, t(a)) -> t(b) ! {| e}

An effect-polymorphic traversal: traverse is an effectful map, the per-element effect row e replacing the classic Applicative parameter.

Effects

Emit

effect Emit(a)
  emit(a) : Unit

The stream effect: emit(x) yields one element to the enclosing consumer.

Output

effect Output
  out_print(String) : Unit
  out_println(String) : Unit

Console output as an interceptable capability. print/println perform these ops; the default run_io handler discharges them to the real terminal, while replay/durable drop them during a replayed prefix.

Console

effect Console
  con_read_int() : Int
  con_read_line() : String

Console input capability. The surface wrappers read_int/read_line perform these ops; run_io discharges each by resuming with the matching prim_* builtin, and the tail-resumptive handlers fuse to direct calls.

FileSystem

effect FileSystem
  fs_read_file(String) : String
  fs_read_bytes(String) : Buf
  fs_file_exists(String) : Bool

File-system read capability (read_file, read_bytes, file_exists).

Random

effect Random
  rng_rand() : Int

Random-number capability (rand).

Env

effect Env
  env_get(String) : String
  env_argc() : Int
  env_arg(Int) : String

Process-environment capability (getenv, args_count, arg).

Instances

eqInt

instance eqInt : Eq(Int)

eqI64

instance eqI64 : Eq(I64)

eqU64

instance eqU64 : Eq(U64)

eqBool

instance eqBool : Eq(Bool)

eqStr

instance eqStr : Eq(String)

eqFloat

instance eqFloat : Eq(Float)

eqChar

instance eqChar : Eq(Char)

ordInt

instance ordInt : Ord(Int)

ordI64

instance ordI64 : Ord(I64)

ordU64

instance ordU64 : Ord(U64)

ordBool

instance ordBool : Ord(Bool)

ordStr

instance ordStr : Ord(String)

ordChar

instance ordChar : Ord(Char)

ordFloat

instance ordFloat : Ord(Float)

eqPair

instance eqPair : Eq((a, b))

ordPair

instance ordPair : Ord((a, b))

eqTriple

instance eqTriple : Eq((a, b, c))

ordTriple

instance ordTriple : Ord((a, b, c))

showInt

instance showInt : Show(Int)

showI64

instance showI64 : Show(I64)

showU64

instance showU64 : Show(U64)

showFloat

instance showFloat : Show(Float)

showBool

instance showBool : Show(Bool)

showStr

instance showStr : Show(String)

showChar

instance showChar : Show(Char)

showUnit

instance showUnit : Show(Unit)

showList

instance showList : Show(List(a))

Lists render in bracket form, [a, b, c], matching the print-site generator; the elements recurse through their own Show.

hashInt

instance hashInt : Hash(Int)

hashI64

instance hashI64 : Hash(I64)

hashU64

instance hashU64 : Hash(U64)

hashBool

instance hashBool : Hash(Bool)

hashChar

instance hashChar : Hash(Char)

hashFloat

instance hashFloat : Hash(Float)

hashStr

instance hashStr : Hash(String)

hashUnit

instance hashUnit : Hash(Unit)

powInt

instance powInt : Pow(Int)

powFloat

instance powFloat : Pow(Float)

numInt

instance numInt : Num(Int)

numI64

instance numI64 : Num(I64)

numU64

instance numU64 : Num(U64)

numFloat

instance numFloat : Num(Float)

divInt

instance divInt : Div(Int)

divI64

instance divI64 : Div(I64)

divU64

instance divU64 : Div(U64)

divFloat

instance divFloat : Div(Float)

functorList

instance functorList : Functor(List)

functorOption

instance functorOption : Functor(Option)

foldableList

instance foldableList : Foldable(List)

foldableOption

instance foldableOption : Foldable(Option)

applicativeList

instance applicativeList : Applicative(List)

applicativeOption

instance applicativeOption : Applicative(Option)

monadList

instance monadList : Monad(List)

monadOption

instance monadOption : Monad(Option)

traversableList

instance traversableList : Traversable(List)

traversableOption

instance traversableOption : Traversable(Option)

Functions and Values

id

id : forall a. (a) -> a

The identity function.

const

const : forall a b. (a, b) -> a

The constant function: returns x, ignoring y.

compose

compose : forall e0 a b c. ((b) -> a ! {e0}, (c) -> b ! {e0}, c) -> a ! {e0}

Function composition: compose(f, g, x) is f(g(x)).

flip

flip : forall e0 a b c. ((b, c) -> a ! {e0}, c, b) -> a ! {e0}

f with its first two arguments swapped.

not

not : (Bool) -> Bool

Boolean negation.

and

and : (Bool, Bool) -> Bool

Boolean conjunction (the function form of &&).

or

or : (Bool, Bool) -> Bool

Boolean disjunction (the function form of ||).

xor

xor : (Bool, Bool) -> Bool

Exclusive or.

abs

abs : (Int) -> Int

Absolute value.

max

max : (Int, Int) -> Int

The greater of two values.

min

min : (Int, Int) -> Int

The lesser of two values.

clamp

clamp : (Int, Int, Int) -> Int

Constrain x to the range [lo, hi].

signum

signum : (Int) -> Int

The sign of n, as -1, 0, or 1.

mod

mod : (Int, Int) -> Int

The remainder a % b.

even

even : (Int) -> Bool

True when n is even.

odd

odd : (Int) -> Bool

True when n is odd.

gcd

gcd : (Int, Int) -> Int

The greatest common divisor (Euclid’s algorithm).

lcm

lcm : (Int, Int) -> Int

The least common multiple.

int_pow_go

int_pow_go : (Int, Int, Int) -> Int

int_pow

int_pow : (Int, Int) -> Int

Integer exponentiation, the Pow(Int) instance: bignum-correct because * promotes past 63 bits, and tail recursive so a large exponent folds in constant stack. a ^ b over ints lowers here through the Pow class. A negative exponent is defined as 1 / a ^ (-b) under the language’s one truncating division rule: 0 whenever the magnitude of the base exceeds 1, the exact reciprocal for a base of 1 or -1, and the division-by-zero fault for a base of 0 (which is exactly what 0 ^ -1 is).

factorial

factorial : (Int) -> Int

n!, the factorial of n.

fib

fib : (Int) -> Int

The nth Fibonacci number (naive, exponential).

pi

pi : Float

Pi. The transcendental functions (sin, cos, tan, the inverse and hyperbolic families, exp, ln, log2, log10, pow, cbrt, …) are owned builtins routing through the vendored libm, identical on every backend; only the named constants live here.

e

e : Float

Euler’s number.

tau

tau : Float

Tau, 2 * pi.

rand_below

rand_below : (Int) -> Int ! {Random}

A random integer in [0, n), over the seeded SplitMix64 stream.

rand_range

rand_range : (Int, Int) -> Int ! {Random}

A random integer in [lo, hi).

rand_bool

rand_bool : () -> Bool ! {Random}

A random boolean.

between

between : (Int, Int, Int) -> Bool

True when lo <= x <= hi.

fst

fst : forall a b. ((a, b)) -> a

The first component of a pair.

snd

snd : forall a b. ((a, b)) -> b

The second component of a pair.

swap

swap : forall a b. ((a, b)) -> (b, a)

A pair with its two components swapped.

pair_map

pair_map : forall e0 a b c d. ((b) -> a ! {e0}, (d) -> c ! {e0}, (b, d)) -> (a, c) ! {e0}

Apply f to the first component and g to the second.

guard

guard : (Bool) -> Unit ! {Fail}

() when b holds, otherwise fail() (short-circuits a failable block).

optional

optional : forall e0 a. (() -> a ! {e0}) -> Option(a) ! {e0}

Run thunk, returning Some(result), or None if it calls fail().

succeeds

succeeds : forall e0 a. (() -> a ! {Fail, e0}) -> Bool ! {e0}

True when thunk runs to completion without calling fail().

default

default : forall e0 a. (() -> a ! {e0}, a) -> a ! {e0}

Run thunk, returning its result or the default d if it calls fail().

at_list

at_list : forall a. (List(a), Int) -> a ! {Fail}

The element at index i, or fail() if out of range. Backs xs[i], so xs.at_list(i) ?? d defaults cleanly through ??.

at_map

at_map : forall a b c. (Map(b, c, a), b) -> c ! {Fail}

The value bound to key, or fail() if absent. Backs m[k].

force

force : forall a. (Option(a)) -> a ! {Fail}

The value inside Some, or fail() for None; o.force() ?? d defaults.

at_array

at_array : forall a. (Array(a), Int) -> a ! {Fail}

The array element at i, or fail() out of bounds. Backs a[i].

at_hashmap

at_hashmap : forall a. (HashMap(a), String) -> a ! {Fail}

The hash-map value for k, or fail() if absent. Backs m[k].

at_byte

at_byte : (String, Int) -> Int ! {Fail}

The byte at index i of a string, or fail() out of bounds. Backs s[i].

list_set

list_set : forall a. (List(a), Int, a) -> List(a)

A new list with element i replaced by v (out of range: unchanged). Backs xs[i] := v and the [i] optic path on lists.

sort

sort : forall a. (List(a)) -> List(a)

Sort a list in ascending order, a stable O(n log n) merge sort. Primitive element types are specialized to a native kernel at the call site; any other Ord type uses the generic path.

while_loop

while_loop : forall e0 a. ((a) -> Bool ! {e0}, (a) -> a ! {e0}, a) -> a ! {e0}

Iterate body from state s while cond(s) holds, returning the final state. Tail-recursive (constant stack).

for_range

for_range : forall e0 a. (Int, Int, (Int, a) -> a ! {e0}, a) -> a ! {e0}

Fold f(i, s) over i in [lo, hi), threading the state s.

repeat_while

repeat_while : forall e0 a. (() -> Bool ! {e0}, () -> a ! {e0}) -> Unit ! {e0}

The driver while c do body (and loop body with break) desugars to. Condition and body are thunks re-run each iteration, closing over the ambient var state; tail-recursive, so it runs in constant stack.

forever

forever : forall e0 a b. (() -> b ! {e0}) -> a ! {e0}

The driver an unconditional loop body (no break) desugars to: it never returns, so its result type is fully polymorphic. Tail-recursive.

repeat

repeat : forall e0 a. (Int, () -> a ! {e0}) -> Unit ! {e0}

Run body n times for its effects.

read_int

read_int : () -> Int ! {Console}

Read an integer from standard input.

read_line

read_line : () -> String ! {Console}

Read a line from standard input.

read_file

read_file : (String) -> String ! {FileSystem}

Read the contents of the file at path p.

read_file_bytes

read_file_bytes : (String) -> Buf ! {FileSystem}

Read the raw bytes of the file at path p as a byte buffer, with no UTF-8 interpretation. Data.Bytes.read_bytes wraps this as the Bytes-typed API.

file_exists

file_exists : (String) -> Bool ! {FileSystem}

True when a file exists at path p.

rand

rand : () -> Int ! {Random}

A random integer.

getenv

getenv : (String) -> String ! {Env}

The value of environment variable s (empty when unset).

args_count

args_count : () -> Int ! {Env}

The number of command-line arguments.

arg

arg : (Int) -> String ! {Env}

The ith command-line argument.

run_io

run_io : forall e0 a. ((Unit) -> a ! {Console, Env, FileSystem, IO, Output, Random, e0}) -> a ! {IO, e0}

The default world handler the entry point is wrapped in. Each capability effect is discharged by a tail-resumptive handler that resumes with the matching prim_* builtin, so the chain fuses to direct calls (no effect-op allocation), leaving only {IO | e}.

srange_go

srange_go : (Int, Int) -> Unit ! {Emit(Int)}

Helper for srange: emit lo, lo+1, ..., hi-1.

srange

srange : forall a. (Int, Int) -> (a) -> Unit ! {Emit(Int)}

A stream of the integers in [lo, hi), for the Emit combinators.

sof_go

sof_go : forall a. (List(a)) -> Unit ! {Emit(a)}

Helper for sof: emit each element of xs.

sof

sof : forall a b. (List(a)) -> (b) -> Unit ! {Emit(a)}

A stream of the elements of the list xs.

enum_from_to

enum_from_to : (Int, Int) -> List(Int)

The ascending list [lo, lo+1, ..., hi] (empty when lo > hi). Backs the [a..z] list syntax.

enum_seq

enum_seq : (Int, Int, Int) -> List(Int)

Helper for enum_from_then_to: the list from x by step up to hi.

enum_from_then_to

enum_from_then_to : (Int, Int, Int) -> List(Int)

The list from a, stepping by b - a, up to hi. Backs the [a,b..z] list syntax.

smap_go

smap_go : forall e0 a b c. ((Unit) -> a ! {Emit(b), e0}, (c) -> b ! {Emit(b), e0}) -> a ! {Emit(b), e0}

Helper for smap.

smap

smap : forall e1 a b c d. ((Unit) -> a ! {Emit(b), e1}, (c) -> b ! {Emit(b), e1}) -> (d) -> a ! {Emit(b), e1}

Map f over every element of a stream, fusing (no intermediate list).

skeep_go

skeep_go : forall e0 a b. ((Unit) -> a ! {Emit(b), e0}, (b) -> Bool ! {Emit(b), e0}) -> a ! {Emit(b), e0}

Helper for skeep.

skeep

skeep : forall e1 a b c. ((Unit) -> a ! {Emit(b), e1}, (b) -> Bool ! {Emit(b), e1}) -> (c) -> a ! {Emit(b), e1}

Keep only the stream elements satisfying p, fusing.

stake_go

stake_go : forall e0 a b. ((Unit) -> a ! {Emit(b), e0}, Int) -> Unit ! {Emit(b), e0}

Helper for stake.

stake

stake : forall e1 a b c. ((Unit) -> b ! {Emit(a), e1}, Int) -> (c) -> Unit ! {Emit(a), e1}

The first n elements of a stream, stopping the producer early.

sfold

sfold : forall e0 a b c. ((Unit) -> b ! {Emit(c), e0}, a, (a, c) -> a ! {e0}) -> a ! {e0}

Left-fold a stream with f from the initial accumulator z, fusing. The stream row is pinned to {Emit(a) | e} so the handler discharges Emit (leaving {e}); without the annotation Emit slips into a bare row variable and leaks past the fold into the caller’s row.

ssum

ssum : forall e0 a. ((Unit) -> a ! {Emit(Int), e0}) -> Int ! {e0}

Sum a stream of numbers.

scollect

scollect : forall e0 a b. ((Unit) -> a ! {Emit(b), e0}) -> List(b) ! {e0}

Collect a stream into a list, in emission order.

concat_map

concat_map : forall e0 a b. ((a) -> List(b) ! {e0}, List(a)) -> List(b) ! {e0}

Map f over xs and concatenate the resulting lists. Kept in the prelude (as well as Data.List) because optic-path desugaring synthesizes calls to it by bare name.

eprintln

eprintln : (String) -> Unit ! {IO}

Print s to standard error, followed by a newline.

push_all

push_all : forall a. (Array(a), List(a)) -> Array(a)

Helper for array_of_list: push each element of xs onto arr.

array_of_list

array_of_list : forall a. (List(a)) -> Array(a)

Build a growable Array from a list.

concat_all

concat_all : (List(String)) -> String

Join a list of strings into one with a single allocation (an O(n) builder that replaces a right-nested chain of concat).

fnv_from

fnv_from : (String, Int, U64) -> U64

Helper for str_hash: fold one byte into the running FNV-1a hash.

str_hash

str_hash : (String) -> U64

The FNV-1a 64-bit hash of a string (the U64 lane wraps, O(length)).

bucket_of

bucket_of : (String, Int) -> Int

Helper: the bucket index of key k in a table of n buckets.

hm_new

hm_new : forall a. () -> HashMap(a)

An empty hash map.

assoc_get

assoc_get : forall a. (List((String, a)), String) -> Option(a)

Helper: look up k in an association-list bucket (matches pairs directly so it keeps working in a program that defines its own fst/snd).

hm_lookup

hm_lookup : forall a. (HashMap(a), String) -> Option(a)

The value bound to k as Some, or None.

hm_member

hm_member : forall a. (HashMap(a), String) -> Bool

True when k is present.

hm_get_or

hm_get_or : forall a. (a, HashMap(a), String) -> a

The value bound to k, or the default d.

assoc_put

assoc_put : forall a. (List((String, a)), String, a) -> (List((String, a)), Int)

Helper for hm_put_raw: replace or add k in a bucket, returning the chain and 1 if the key was new (0 if it replaced a binding).

hm_put_raw

hm_put_raw : forall a. (HashMap(a), String, a) -> HashMap(a)

Helper for hm_insert: insert without resizing.

buckets_to_list

buckets_to_list : forall a. (Array(List(a)), Int, Int) -> List(a)

Helper for hm_to_list: concatenate buckets i..n.

hm_to_list

hm_to_list : forall a. (HashMap(a)) -> List((String, a))

The (key, value) pairs, in bucket order.

pair_keys

pair_keys : forall a b. (List((a, b))) -> List(a)

Helper: the keys of a list of pairs.

hm_keys

hm_keys : forall a. (HashMap(a)) -> List(String)

The keys of the map.

hm_size

hm_size : forall a. (HashMap(a)) -> Int

The number of entries.

hm_reinsert

hm_reinsert : forall a. (HashMap(a), List((String, a))) -> HashMap(a)

Helper for hm_insert: re-insert every pair into a fresh table.

hm_insert

hm_insert : forall a. (HashMap(a), String, a) -> HashMap(a)

Insert or overwrite k, doubling the bucket count and rehashing once the load factor exceeds 1.

hm_delete

hm_delete : forall a. (HashMap(a), String) -> HashMap(a)

Remove k (a no-op if absent).

assoc_del

assoc_del : forall a. (List((String, a)), String) -> (List((String, a)), Int)

Helper for hm_delete: remove k from a bucket, returning the chain and 1 if a binding was removed.

pair_values

pair_values : forall a b. (List((a, b))) -> List(b)

Helper: the values of a list of pairs.

hm_values

hm_values : forall a. (HashMap(a)) -> List(a)

The values of the map.

hm_from_list_go

hm_from_list_go : forall a. (HashMap(a), List((String, a))) -> HashMap(a)

Helper for hm_from_list.

hm_from_list

hm_from_list : forall a. (List((String, a))) -> HashMap(a)

Build a hash map from (key, value) pairs (later pairs win).

hm_adjust

hm_adjust : forall e0 a. ((a) -> a ! {e0}, HashMap(a), String) -> HashMap(a) ! {e0}

Apply f to the value at k if present, otherwise leave the map unchanged.

array_foldl_go

array_foldl_go : forall e0 a b. ((a, b) -> a ! {e0}, a, Array(b), Int) -> a ! {e0}

Helper for array_foldl.

array_foldl

array_foldl : forall e0 a b. ((a, b) -> a ! {e0}, a, Array(b)) -> a ! {e0}

Left-fold f over the elements of an array from acc.

array_to_list_go

array_to_list_go : forall a. (Array(a), Int, List(a)) -> List(a)

Helper for array_to_list.

array_to_list

array_to_list : forall a. (Array(a)) -> List(a)

The elements of an array as a list, in order.

args_go

args_go : (Int, Int) -> List(String) ! {Env}

Helper for args.

args

args : () -> List(String) ! {Env}

The command-line arguments as a list.

int_cmp

int_cmp : (Int, Int) -> Int

Three-way comparison of two ints: -1, 0, or 1 (the Ord(Int) kernel).

str_escape

str_escape : (String) -> String

Render s as a canonical double-quoted string literal, escaping the characters that would otherwise break the quoting. This is what show produces for a String; raw output (print/println of a message) is unquoted.

escape_body

escape_body : (String, Int, Int) -> String

escape_at

escape_at : (Int, String, Int) -> String

show_list_body

show_list_body : forall a. (List(a), Bool) -> String

insert_by_ord

insert_by_ord : forall a. (a, List(a)) -> List(a)

Insert x into an already-sorted list, keeping it sorted (Ord).

merge_by_ord

merge_by_ord : forall a. (List(a), List(a)) -> List(a)

Stable merge of two already-sorted lists. The recursive Cons becomes a loop by tail-recursion-modulo-cons, and Perceus reuses the consumed cells.

sort_by_ord

sort_by_ord : forall a. (List(a)) -> List(a)

The generic stable merge sort behind sort, for any Ord element type.