Verified
High-level combinators for writing kernel-checked implementations.
Write programs with these combinators, then call v.verify to
type-check and extract a Nix function that is correct by construction.
Example
# Verified successor: Nat → Nat
v.verify (H.forall "x" H.nat (_: H.nat))
(v.fn "x" H.nat (x: H.succ x))
# → Nix function: n → n + 1
Literals
nat : Int → Hoas— natural number literal (S^n(zero))str : String → Hoas— string literalint_ : Int → Hoas— integer literalfloat_ : Float → Hoas— float literaltrue_,false_— boolean literalsnull_— unit value (tt)
Binding
fn : String → Hoas → (Hoas → Hoas) → Hoas— lambda abstractionlet_ : String → Hoas → Hoas → (Hoas → Hoas) → Hoas— let binding
Data Operations
pair,fst,snd— Σ-type construction and projectionfield : Hoas → String → Hoas → Hoas— record field projection by nameinl,inr— Sum injectionapp— function application
Eliminators (Constant Motive)
These auto-generate the motive λ_.resultTy, so you only supply
the result type and the branches:
if_ : Hoas → Hoas → { then_; else_; } → Hoas— Bool eliminationmatch : Hoas → Hoas → { zero; succ : k → ih → Hoas; } → Hoas— Nat eliminationmatchList : Hoas → Hoas → Hoas → { nil; cons : h → t → ih → Hoas; } → Hoas— List eliminationmatchSum : Hoas → Hoas → Hoas → Hoas → { left; right; } → Hoas— Sum elimination
Derived Combinators
map : Hoas → Hoas → Hoas → Hoas → Hoas— map f over a listfold : Hoas → Hoas → Hoas → Hoas → Hoas → Hoas— fold over a listfilter : Hoas → Hoas → Hoas → Hoas— filter a list by predicate
Pipeline
verify : Hoas → Hoas → NixValue— type-check + eval + extractverifiedFn : Hoas → Hoas → VerifiedValue— callable value with_hoasImplfor full kernel body verification in parent types
app
app: HOAS function application — app f arg builds the redex; β-reduces during normalisation when f is a lambda.
app : Hoas -> Hoas -> Hoas
false_
false: HOAS literal — the False constructor of H.bool as inl tt; reflects the bool-as-sum levitation discipline._
false_ : Hoas
field
field: HOAS record field-projection by name — derives the universal-property eliminator for a mono-constructor datatype and applies it to extract the named field.
field : Hoas -> String -> Hoas -> Hoas
Requires recordTy to carry _dtypeMeta with exactly one
constructor (records are mono-constructor datatypes via
H.record). Throws at build time if the type is
multi-constructor, has no fields, or the requested field name
is absent. The 1-field special case reduces via ι
(elim P (λa.a) (mk a) ≡ a); no surface branching is needed.
Field positions are read from meta.constructors[0].fields in
declaration order, so renaming a field in source is a
breaking change.
filter
filter: HOAS list-filter combinator — keeps elements where pred : elemTy -> Bool returns true_; built on listElim plus per-element boolElim.
filter : Hoas -> Hoas -> Hoas -> Hoas
Annotates pred with H.forall "_" elemTy (_: H.bool) so
the application infers. pred must be a HOAS function term
producing a bool HOAS value (e.g. via if_, match, or a
direct true_/false_). Element order is preserved; the
accumulator threads via the inductive hypothesis.
float_
float: HOAS literal — lift a Nix float to a floatLit HOAS term checkable against H.float_._
float_ : Float -> Hoas
fn
fn: HOAS lambda — fn name domTy body builds λ(name:domTy). body, with body a Nix function receiving the bound variable as a HOAS term.
fn : String -> Hoas -> (Hoas -> Hoas) -> Hoas
fold
fold: HOAS list-fold combinator — combines elements right-to-left using f : elemTy -> resultTy -> resultTy starting from init.
fold : Hoas -> Hoas -> Hoas -> Hoas -> Hoas -> Hoas
Annotates f with H.forall "_" elemTy (_: H.forall "_" resultTy (_: resultTy))
so the applications f h ih infer correctly. f must be a
HOAS function term built with fn (or nested fn for the
curried two-argument case). The accumulator threads through
ih; the empty-list case returns init.
fst
fst: first projection on a HOAS Σ-pair; reduces by π₁ during normalisation.
fst : Hoas -> Hoas
if_
if: bool-elimination wrapper — supplies a constant motive λ_.resultTy so callers write only the result type and the two branches._
if_ : Hoas -> Hoas -> { then_ : Hoas; else_ : Hoas; } -> Hoas
Use when the branch result type does not depend on the
scrutinee. For a dependent motive (different result type per
branch), drop to H.boolElim directly. The synthesised motive
is λ_:bool.resultTy; boolElim's level argument is fixed at
0 here, so cross-universe branching also needs H.boolElim.
inl
inl: HOAS sum left-injection — inl leftTy rightTy term builds an A + B term carrying term : A in the left branch.
inl : Hoas -> Hoas -> Hoas -> Hoas
inr
inr: HOAS sum right-injection — inr leftTy rightTy term builds an A + B term carrying term : B in the right branch.
inr : Hoas -> Hoas -> Hoas -> Hoas
int_
int: HOAS literal — lift a Nix integer to an intLit HOAS term checkable against H.int_ (the kernel Int axiom, distinct from nat)._
int_ : Int -> Hoas
let_
let: HOAS let binding — let_ name ty val body builds let name : ty = val in body; body is a Nix function receiving the bound variable._
let_ : String -> Hoas -> Hoas -> (Hoas -> Hoas) -> Hoas
makeRecord
makeRecord: HOAS record construction by name — applies the mono-constructor of a μ-encoded record type to the field values in declaration order, dual to field's named projection.
makeRecord : Hoas -> { <field> = Hoas; ... } -> Hoas
Dual to field. Given a record type built by H.record (or
any mono-constructor datatype carrying _dtypeMeta) and an
attrset keyed by field name, produces the HOAS term
mk a₀ … aₙ₋₁ where each aᵢ is read from argsAttrs
by field name, and
field order follows meta.constructors[0].fields (for
H.record, alphabetical by name).
Throws at build time on a multi-constructor datatype, a
missing required field, or an unknown extra field. The
constructor term used is meta.constructors[0].ctor, exposed
on the kernel datatype attrset by _datatypeImpl.
Use this in verified implementations that return records, so
consumer code never needs to reach for builtins.foldl' H.app
DT.mk [...] or know the μ-encoding.
map
map: HOAS list-map combinator built on listElim — applies f : elemTy -> resultTy to every element, threading the inductive hypothesis to accumulate the output list.
map : Hoas -> Hoas -> Hoas -> Hoas -> Hoas
Annotates f with H.forall "_" elemTy (_: resultTy) so the
kernel can infer the application type. f must be a HOAS
function term (build one with fn), not a Nix function. For
element transformations that aren't expressible as a uniform
HOAS function (e.g. type-dependent on element shape), drop to
H.listElim directly.
match
match: nat-elimination wrapper — supplies a constant motive λ_.resultTy; the succ callback receives both predecessor k and inductive hypothesis ih.
match : Hoas -> Hoas -> { zero : Hoas; succ : Hoas -> Hoas -> Hoas; } -> Hoas
The succ callback receives two HOAS values: k (the
predecessor binder, of type nat) and ih (the inductive
hypothesis, of type resultTy). Use when result type is
non-dependent on the scrutinee; drop to H.ind for dependent
motives. Level is fixed at 0 by the synthesised motive.
matchList
matchList: list-elimination wrapper — constant motive λ_.resultTy; the cons callback binds head, tail, and inductive hypothesis.
matchList : Hoas -> Hoas -> Hoas -> { nil : Hoas; cons : Hoas -> Hoas -> Hoas -> Hoas; } -> Hoas
The cons callback receives three HOAS values: h (the head
element of type elemTy), t (the tail list of type
listOf elemTy), and ih (the inductive hypothesis of type
resultTy). For dependent motives, drop to H.listElim.
Level fixed at 0.
matchSum
matchSum: sum-elimination wrapper — constant motive λ_.resultTy; the left and right callbacks receive their respective payloads.
matchSum : Hoas -> Hoas -> Hoas -> Hoas -> { left : Hoas -> Hoas; right : Hoas -> Hoas; } -> Hoas
Each callback receives one HOAS value: the left payload for
left, the right payload for right. Use when the result
type doesn't depend on which case fires; drop to H.sumElim
for dependent motives. Level fixed at 0.
nat
nat: HOAS literal — wrap a Nix Int as a succ^n zero natural-number HOAS term checkable against H.nat.
nat : Int -> Hoas
null_
null: HOAS literal — the unique inhabitant tt of H.unit; the conventional empty / placeholder value in verified code._
null_ : Hoas
pair
pair: HOAS Σ-pair constructor — pair fst snd packages two HOAS values; the surrounding annotation fixes which Σ-type the pair inhabits.
pair : Hoas -> Hoas -> Hoas
snd
snd: second projection on a HOAS Σ-pair; reduces by π₂ during normalisation.
snd : Hoas -> Hoas
str
str: HOAS literal — lift a Nix String to a stringLit HOAS term checkable against H.string.
str : String -> Hoas
strElem
strElem: HOAS membership check on a List String — folds strEq target across the list, accumulating true_ if any element matches.
strElem : Hoas -> Hoas -> Hoas
Built on fold plus strEq: each list element is compared
to target; the accumulator starts at false_ and stays
true_ once a match is seen. Use when verified code needs a
membership predicate over strings; for raw kernel-level
equality on a single pair, use strEq.
strEq
strEq: kernel string equality returning a Bool HOAS term; reflects the mkStrEq primitive of the kernel.
strEq : Hoas -> Hoas -> Hoas
true_
true: HOAS literal — the True constructor of H.bool as inr tt; reflects the bool-as-sum levitation discipline._
true_ : Hoas
verifiedFn
verifiedFn: extract a kernel-verified callable carrying _hoasImpl — elaborateValue's Pi case uses the HOAS body for full re-verification instead of falling back to an opaque trust boundary.
verifiedFn : Hoas -> Hoas -> { __functor; _hoasImpl }
Returns an attrset callable via __functor (so
(verifiedFn piTy body) arg works) and carrying
_hoasImpl = body so parent elaboration can re-check the body
against a more general type instead of treating it as an
opaque lambda. Use when the verified function will be
embedded inside another verified type-check (e.g. as a field
of a verified record); for standalone use, verify is
simpler.
verify
verify: full pipeline — kernel-check a HOAS implementation against a HOAS type, then evaluate and extract a Nix value witnessing the body.
verify : Hoas -> Hoas -> NixValue
Calls fx.tc.elaborate.verifyAndExtract internally. Returns
the Nix value (typically a function or data structure) that
the type-checked HOAS body denotes; consume via normal Nix
call or attribute access. Use as the final step of a
verified-implementation pipeline. For a callable wrapper that
retains the HOAS implementation so parent-type elaboration can
re-check the body, use verifiedFn instead.