Verbs and local transitions #
Def:verb–selection (main.tex:1034–1112); D/OP (1055–1076);
Def:NockProgram (1090–1098); operators (1514–1626); Nock (1639–1661).
Equations
- Nock.instReprAction = { reprPrec := Nock.instReprAction.repr }
Equations
- Nock.instReprAction.repr Nock.Action.null prec✝ = Repr.addAppParen (Std.Format.nest (if prec✝ ≥ 1024 then 1 else 2) (Std.Format.text "Nock.Action.null")).group prec✝
- Nock.instReprAction.repr Nock.Action.star prec✝ = Repr.addAppParen (Std.Format.nest (if prec✝ ≥ 1024 then 1 else 2) (Std.Format.text "Nock.Action.star")).group prec✝
- Nock.instReprAction.repr Nock.Action.wut prec✝ = Repr.addAppParen (Std.Format.nest (if prec✝ ≥ 1024 then 1 else 2) (Std.Format.text "Nock.Action.wut")).group prec✝
- Nock.instReprAction.repr Nock.Action.equal prec✝ = Repr.addAppParen (Std.Format.nest (if prec✝ ≥ 1024 then 1 else 2) (Std.Format.text "Nock.Action.equal")).group prec✝
- Nock.instReprAction.repr Nock.Action.slot prec✝ = Repr.addAppParen (Std.Format.nest (if prec✝ ≥ 1024 then 1 else 2) (Std.Format.text "Nock.Action.slot")).group prec✝
- Nock.instReprAction.repr Nock.Action.edit prec✝ = Repr.addAppParen (Std.Format.nest (if prec✝ ≥ 1024 then 1 else 2) (Std.Format.text "Nock.Action.edit")).group prec✝
- Nock.instReprAction.repr Nock.Action.minus prec✝ = Repr.addAppParen (Std.Format.nest (if prec✝ ≥ 1024 then 1 else 2) (Std.Format.text "Nock.Action.minus")).group prec✝
Instances For
Equations
- Nock.instInhabitedAction = { default := Nock.instInhabitedAction.default }
Equations
- One or more equations did not get rendered due to their size.
Instances For
Equations
- Nock.instReprVerb = { reprPrec := Nock.instReprVerb.repr }
Equations
- One or more equations did not get rendered due to their size.
- Nock.instDecidableEqVerb.decEq (Nock.Verb.leaf a) (Nock.Verb.leaf b) = if h : a = b then h ▸ isTrue ⋯ else isFalse ⋯
- Nock.instDecidableEqVerb.decEq (Nock.Verb.leaf a) (Nock.Verb.node a_1 a_2 a_3) = isFalse ⋯
- Nock.instDecidableEqVerb.decEq (Nock.Verb.node a a_1 a_2) (Nock.Verb.leaf a_3) = isFalse ⋯
Instances For
Equations
- Nock.instInhabitedVerb = { default := Nock.instInhabitedVerb.default }
The underlying noun (snd of the verb pair): forget the action labels.
Equations
- (Nock.Verb.leaf n).noun = Nock.Noun.atom n
- (Nock.Verb.node a l r).noun = l.noun.cell r.noun
Instances For
Number of leaves λ of the verb's noun.
Equations
- (Nock.Verb.leaf n).leaves = 1
- (Nock.Verb.node a l r).leaves = l.leaves + r.leaves
Instances For
type (main.tex:1045): is the underlying noun a cell?
Equations
- (Nock.Verb.node a a_1 a_2).isCell = true
- (Nock.Verb.leaf a).isCell = false
Instances For
Root action, if the verb is a cell (none at a leaf — leaves carry no action).
Equations
- (Nock.Verb.node a a_1 a_2).rootAction = some a
- (Nock.Verb.leaf a).rootAction = none
Instances For
Is the root action a pending *?
Equations
- (Nock.Verb.node Nock.Action.star a a_1).isStar = true
- x✝.isStar = false
Instances For
Does the root node carry a pending (non-⊥) action? * or any operator counts;
a leaf or a ⊥-node does not.
Equations
- (Nock.Verb.node a a_1 a_2).isPending = !a.isNull
- (Nock.Verb.leaf a).isPending = false
Instances For
Def:verb (main.tex:1039).
verb is (fully) executed or in terminal state if its actions array consists only of ⊥.
Equations
- (Nock.Verb.leaf n).isTerminal = true
- (Nock.Verb.node a l r).isTerminal = (a.isNull && l.isTerminal && r.isTerminal)
Instances For
Selection (main.tex:1103–1112) #
Selection (main.tex:1103–1112).
map := DFS; index of each internal node is the order a DFS from the root first explores
it, excluding leaves.
Equations
Instances For
Selection (main.tex:1103–1112).
map := DFS: returns the verb at internal-node index i ∈ [λ−1].
Equations
- Nock.Verb.map i v = Nock.Verb.findAt i v.nodes
Instances For
Selection (main.tex:1103–1112).
getIndex^Λ(F) = argmax_{map(i,F) ∈ NockProgram^Λ}(map(i,F)); F₁ >_F F₂ ⇔ i₁ > i₂.
Equations
Instances For
Rebuild v, replacing the internal node at DFS index i by new.
Equations
- One or more equations did not get rendered due to their size.
- Nock.Verb.replaceAux i new (Nock.Verb.leaf a) x✝ = (x✝, Nock.Verb.leaf a)
Instances For
Splice: replace the subverb at DFS index i with new.
Equations
- Nock.Verb.replaceAt i v new = (Nock.Verb.replaceAux i new v 0).snd
Instances For
type(i) = atom ∧ i ∈ [11], or type(i) = cell (⇒ the cons opcode).
Equations
- (Nock.Verb.leaf n).opHeadOk = decide (n < 11)
- (Nock.Verb.node a l r).opHeadOk = true
Instances For
Algorithm:Opcode_Updates_verb domain D (main.tex:1055–1058, 1078–1083).
D := {v := (a,n) | n := [n₁,[i,n₂]], (i∈[11]) ∪ (type(i)=cell), a₁=⟨*⟩, ∀j≠1 aⱼ=⟨⊥⟩};
(1) v := *[n₁,[i,n₂]]; (2) n₁,[i,n₂] terminal; (3) i atom in [11] or cell.
Equations
- (Nock.Verb.node Nock.Action.star n1 (Nock.Verb.node ra i n2)).inOpcodeDomain = (n1.isTerminal && ra.isNull && i.isTerminal && n2.isTerminal && i.opHeadOk)
- x✝.inOpcodeDomain = false
Instances For
A node ready for an operator-application step: it carries an operator from X
and both of its argument subtrees are already in terminal state (note 2b). These are
the operator redexes that the paper's App A transition algorithm elides.
Equations
- (Nock.Verb.node a a_1 a_2).opReady = (a.isOperator && a_1.isTerminal && a_2.isTerminal)
- (Nock.Verb.leaf a).opReady = false
Instances For
The full domain of the transition function next: opcode redexes (inOpcodeDomain,
= the paper's D) together with ready operator nodes (opReady). See note 2c;
Trace.domain (Lem:domain) concludes membership here.
Equations
- v.inDomain = (v.inOpcodeDomain || v.opReady)
Instances For
Opcode local rewrite (main.tex:1060–1076) #
Algorithm:Opcode_Updates_verb (main.tex:1060–1076).
OP₀: *[n₁,[0,n₂]] → /(n₂,n₁); OP₁ → n₂; OP₂ → *[*[n₁,h],*[n₁,t]];
OP₃ → -[3,*[n₁,n₂]]; OP₄ → -[4,*[n₁,n₂]]; OP₅ → =(*[n₁,h],*[n₁,t]);
OP₆ → *[n₁,*[t,[0,*[[2,3],[0,*[n₁,[4,[4,h]]]]]]]]; OP₇ → *[*[n₁,h],t];
OP₈ → *[[*[n₁,h],n₁],t]; OP₉ → *[*[n₁,t],2,[[0,1],0,h]];
OP₁₀ → #[hh,*[n₁,th],*[n₁,t]]; cons: *[n₁,[i,n₂]] → [*[n₁,i],*[n₁,n₂]].
Equations
- One or more equations did not get rendered due to their size.
- (Nock.Verb.node Nock.Action.star n1 (Nock.Verb.node ra (Nock.Verb.leaf 0) n2)).redex = some (Nock.Verb.node Nock.Action.slot n2 n1)
- (Nock.Verb.node Nock.Action.star n1 (Nock.Verb.node ra (Nock.Verb.leaf 1) n2)).redex = some n2
- (Nock.Verb.node Nock.Action.star n1 (Nock.Verb.node ra (Nock.Verb.leaf 2) n2)).redex = none
- (Nock.Verb.node Nock.Action.star n1 (Nock.Verb.node ra (Nock.Verb.leaf 3) n2)).redex = some (Nock.Verb.node Nock.Action.minus (Nock.Verb.leaf 3) (Nock.Verb.node Nock.Action.star n1 n2))
- (Nock.Verb.node Nock.Action.star n1 (Nock.Verb.node ra (Nock.Verb.leaf 4) n2)).redex = some (Nock.Verb.node Nock.Action.minus (Nock.Verb.leaf 4) (Nock.Verb.node Nock.Action.star n1 n2))
- (Nock.Verb.node Nock.Action.star n1 (Nock.Verb.node ra (Nock.Verb.leaf 5) n2)).redex = none
- (Nock.Verb.node Nock.Action.star n1 (Nock.Verb.node ra (Nock.Verb.leaf 6) n2)).redex = none
- (Nock.Verb.node Nock.Action.star n1 (Nock.Verb.node ra (Nock.Verb.leaf 7) (Nock.Verb.node a b c))).redex = some (Nock.Verb.node Nock.Action.star (Nock.Verb.node Nock.Action.star n1 b) c)
- (Nock.Verb.node Nock.Action.star n1 (Nock.Verb.node ra (Nock.Verb.leaf 7) n2)).redex = none
- (Nock.Verb.node Nock.Action.star n1 (Nock.Verb.node ra (Nock.Verb.leaf 8) n2)).redex = none
- (Nock.Verb.node Nock.Action.star n1 (Nock.Verb.node ra (Nock.Verb.leaf 9) n2)).redex = none
- (Nock.Verb.node Nock.Action.star n1 (Nock.Verb.node ra (Nock.Verb.leaf 10) (Nock.Verb.node a b c))).redex = none
- (Nock.Verb.node Nock.Action.star n1 (Nock.Verb.node ra (Nock.Verb.leaf 10) n2)).redex = none
- (Nock.Verb.node Nock.Action.star n1 (Nock.Verb.node ra (Nock.Verb.leaf a) n2)).redex = none
- x✝.redex = none
Instances For
Operator-application steps (Algorithm:Noun_Operators / Unroll_Operator) #
Convert a plain noun into a terminal verb (all actions ⊥).
Equations
Instances For
Local rewrite (main.tex:1060–1076, 1514–1626) #
Algorithm:Noun_Operators / Unroll_Operator (main.tex:1514–1626).
Local rewrite: * via opcodes, or =, /, #, - (-[3,·]=?, -[4,·]=+) on terminal
args.
Equations
- One or more equations did not get rendered due to their size.
- (Nock.Verb.node Nock.Action.star n1 t).reduce = (Nock.Verb.node Nock.Action.star n1 t).redex
- (Nock.Verb.node Nock.Action.equal l r).reduce = some (Nock.Verb.ofNoun (l.noun.tis r.noun))
- (Nock.Verb.node Nock.Action.slot l r).reduce = match l.noun with | Nock.Noun.atom ax => Option.map Nock.Verb.ofNoun (Nock.Noun.slot ax r.noun) | x => none
- (Nock.Verb.node Nock.Action.edit l (Nock.Verb.node a nw od)).reduce = Option.map Nock.Verb.ofNoun (Nock.Noun.edit ax nw.noun od.noun)
- (Nock.Verb.node Nock.Action.edit l r✝).reduce = none
- (Nock.Verb.node Nock.Action.wut a a_1).reduce = none
- (Nock.Verb.node Nock.Action.null a a_1).reduce = none
- (Nock.Verb.leaf a).reduce = none
Instances For
One Nock step. Locate the pending redex of largest DFS index via getIndex/map; if it
lies in the transition domain D (opcode redex or ready operator), apply the local
rewrite (reduce) and splice the result back; otherwise crash (none).
next v = none also when v is terminal (no pending action). Being a Lean function,
next is deterministic — the concrete realization of the paper's "* is a
deterministic mapping between program states".
Equations
- One or more equations did not get rendered due to their size.
Instances For
Def:NockProgram (main.tex:1090–1098).
F = *[subject, formula] with subject, formula terminal; NockProgram^Λ := {F | λ ≤ Λ}.
Equations
- Nock.Verb.program subject formula = Nock.Verb.node Nock.Action.star (Nock.Verb.ofNoun subject) (Nock.Verb.ofNoun formula)
Instances For
Extract the observable output of a stuck verb: its underlying noun if it is in terminal
state (a valid completion, main.tex:1123), else none (a crash / invalid
completion, main.tex:1124).
Instances For
Fuel-indexed iteration of next from v to a terminal/⊥ state, returning the result
noun (none on crash or fuel exhaustion). Nock is Turing-complete, so fuel is
required for totality; none conflates a genuine crash with fuel exhaustion, exactly
as evalN does.
Equations
- Nock.Verb.run 0 x✝ = none
- Nock.Verb.run fuel.succ x✝ = match x✝.next with | some v' => Nock.Verb.run fuel v' | none => x✝.result
Instances For
Run a Nock program *[subject, formula] through the paper's small-step interpreter.
Equations
- Nock.Verb.runProgram fuel subject formula = Nock.Verb.run fuel (Nock.Verb.program subject formula)
Instances For
Strictness of the DFS order (main.tex:1107) #
DFS indices are distinct (main.tex:1107) #
getIndex = numeric argmax of pending indices (spec of maximumPendingIndex) #
Strict redex-selection order (main.tex:1105-1109, 1156) #
i is a maximal pending index of a under the order lt: a pending index that no
other pending index exceeds. This is the paper's argmax characterization of
getIndex.
Equations
- Nock.Verb.IsMaxPending lt a i = (a.IsPendingIdx i ∧ ∀ (j : Nat), a.IsPendingIdx j → ¬lt i j)
Instances For
An abstract redex-selection step: pick a maximal pending index i under lt, and
if the selected subverb is in the transition domain, apply the local rewrite and splice
it back. With no strictness assumption this relation can be multi-valued (several
maximal redexes); SelStep.det shows a strict order collapses it to a function.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Determinism from strictness. If lt is a strict total order, a redex-selection
step is deterministic: hs.total forces the two selected indices to coincide; the rest
is functionality of map/reduce/replaceAt.
The concrete DFS order on pre-order indices is the usual strict order on Nat.
Equations
- Nock.Verb.dfsLt x1✝ x2✝ = (x1✝ < x2✝)
Instances For
The DFS index order is a strict total order. This is why map = DFS "enforces a
strict ordering on subtrees" (main.tex:1107): distinct internal nodes get distinct Nat
indices (enum_index_range/map_of_mem_nodes), and Nat.lt is a strict total order.
Pending-index membership, in list form. The ← direction uses DFS distinctness
(map_of_mem_nodes): a pending node in the nodes list is retrieved by map on its
(unique) index.
getIndex is exactly the DFS argmax: getIndex a = some i ↔ i is the maximal pending
index under dfsLt. (Combines the maximumPendingIndex spec with DFS distinctness.)
Non-strict selection witness (main.tex:2325) #
The empty order — not total, hence not a StrictSelect. Every index is vacuously
maximal under it.
Equations
- Nock.Verb.emptyLt x✝¹ x✝ = False
Instances For
A verb with two independent, equally-maximal redexes: two copies of *[0, [1, 5]]
(each an OP₁ redex reducing to 5), spliced under a ⊥ root.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Non-vacuity of strictness. Under a non-strict order, SelStep is not a function:
it relates twoRedex to two distinct successors. Contrast SelStep.det, which uses
StrictSelect.total to collapse exactly this ambiguity.
Terminal verbs cannot step (main.tex:1039, 1122) #
getIndex of a terminal verb is none: no internal node carries a pending action.
A terminal verb cannot take a Nock step.
Converses: no pending redex ⇒ terminal (main.tex:1122) #
getIndex is none iff terminal. The ← is getIndex_none_of_terminal; the →
is terminal_of_enum_nonpending fed the maximumPendingIndex emptiness spec.
Subtree enumeration embeds. If sub is enumerated at index i within v (counter
c), then every internal node of sub's own enumeration (counter i) also appears in
v's enumeration. This is what lets a pending node inside the selected redex be seen as
a pending index of the whole verb.
The selected redex has terminal children. If getIndex v = some i picks the argmax
pending node map i v = node a l r, then l and r are terminal: any pending node below
them would have a strictly larger DFS index (enum_index_range + enum_subtree_mem),
contradicting maximality (getIndex_eq_some_iff). This is the shape inDomain/reduce
need at the redex.
NockVMROM without OP₁₀ (main.tex:1160) #
The ROM local rewrite: identical to reduce except every part of OP₁₀ (edit, # —
main.tex:1071,1587) is rejected (none = crash), removing the ability to write to memory.
Two things are excluded, exactly the two halves of OP₁₀ in our two-step encoding
(note 2b): (i) the OP₁₀ opcode redex *[n₁,[10,n₂]] (i = 10), and (ii) the edit
operator node it produces (#, the actual memory write). No other opcode produces edit,
so this removes OP₁₀ and nothing else.
Equations
- (Nock.Verb.node Nock.Action.star a (Nock.Verb.node a_1 (Nock.Verb.leaf 10) a_2)).reduceROM = none
- (Nock.Verb.node Nock.Action.edit a a_1).reduceROM = none
- x✝.reduceROM = x✝.reduce
Instances For
One NockVMROM step: exactly next, but using reduceROM for the local rewrite, so a
selected OP₁₀ redex (or a stray edit node) crashes. Every non-crashing ROM step is a
genuine Nock step (next_of_nextROM).
Equations
- One or more equations did not get rendered due to their size.
Instances For
A terminal verb cannot take a ROM step either.
Two-verb transition checker Nock (main.tex:1639–1661) #
Algorithm:Transition_Function (main.tex:1639–1661).
Nock(Tᵢ,Tᵢ₊₁): Fᵢ ← map(Tᵢ,getIndex(Tᵢ)); frame Tᵢ\Fᵢ = Tᵢ₊₁\Fᵢ₊₁;
accept (0) iff Fᵢ₊₁ = OP:Fᵢ / cons:Fᵢ, or Fᵢ₊₁=⊥ when out of domain.
Equations
- One or more equations did not get rendered due to their size.
Instances For
NockCheck ↔ forward semantics + crash. The two-verb checker accepts (a, b)
(returns true = the paper's 0) iff b is a genuine one-step successor of a
(next a = some v, i.e. Step a v) OR a crashes and b = ⊥ (b = none). This is a
genuine biconditional: NockCheck is 1-1 with next (on non-⊥ successors) together with
the crash branch — the checker Nock(Tᵢ,Tᵢ₊₁)=0 and the forward map coincide exactly.
Frame-invariance gate (main.tex:1642) #
Frame agreement at index i: Tj is Ti with the subverb at DFS index i replaced
by some Fj — so Ti and Tj share the same frame (context) outside i. This is the
map-complement equality Ti \ Fᵢ = Tj \ Fⱼ (main.tex:1642).
Equations
- Nock.Verb.FrameAgree i Ti Tj = ∃ (Fj : Nock.Verb), Tj = Nock.Verb.replaceAt i Ti Fj
Instances For
Accepted steps pass the frame gate (main.tex:1642). If NockCheck accepts a non-⊥
successor b of a, then b agrees with a outside the selected index: FrameAgree.
(The genuine-step branch of NockCheck is exactly the frame-preserving splice.)
Verifiable crash — a three-way outcome (value / crash / timeout) #
run/runProgram return Option Noun, collapsing a genuine crash (a stuck, non-terminal ⊥ state,
main.tex:1124) and fuel exhaustion into the same none. eval refines that: it mirrors run's
fuel structure exactly, but at a halt (next v = none) it reports value (a terminal completion)
or
crash (a checked ⊥) instead of some/none; only a genuinely-steppable state can timeout. A
crash thus becomes a positive, kernel-checkable outcome, not merely the absence of a value.
Equations
- One or more equations did not get rendered due to their size.
- Nock.Verb.instReprOutcome.repr Nock.Verb.Outcome.crash prec✝ = Repr.addAppParen (Std.Format.nest (if prec✝ ≥ 1024 then 1 else 2) (Std.Format.text "Nock.Verb.Outcome.crash")).group prec✝
- Nock.Verb.instReprOutcome.repr Nock.Verb.Outcome.timeout prec✝ = Repr.addAppParen (Std.Format.nest (if prec✝ ≥ 1024 then 1 else 2) (Std.Format.text "Nock.Verb.Outcome.timeout")).group prec✝
Instances For
Equations
- Nock.Verb.instReprOutcome = { reprPrec := Nock.Verb.instReprOutcome.repr }
Equations
- Nock.Verb.instDecidableEqOutcome.decEq (Nock.Verb.Outcome.value a) (Nock.Verb.Outcome.value b) = if h : a = b then h ▸ isTrue ⋯ else isFalse ⋯
- Nock.Verb.instDecidableEqOutcome.decEq (Nock.Verb.Outcome.value n) Nock.Verb.Outcome.crash = isFalse ⋯
- Nock.Verb.instDecidableEqOutcome.decEq (Nock.Verb.Outcome.value n) Nock.Verb.Outcome.timeout = isFalse ⋯
- Nock.Verb.instDecidableEqOutcome.decEq Nock.Verb.Outcome.crash (Nock.Verb.Outcome.value n) = isFalse ⋯
- Nock.Verb.instDecidableEqOutcome.decEq Nock.Verb.Outcome.crash Nock.Verb.Outcome.crash = isTrue ⋯
- Nock.Verb.instDecidableEqOutcome.decEq Nock.Verb.Outcome.crash Nock.Verb.Outcome.timeout = isFalse Nock.Verb.instDecidableEqOutcome.decEq._proof_7
- Nock.Verb.instDecidableEqOutcome.decEq Nock.Verb.Outcome.timeout (Nock.Verb.Outcome.value n) = isFalse ⋯
- Nock.Verb.instDecidableEqOutcome.decEq Nock.Verb.Outcome.timeout Nock.Verb.Outcome.crash = isFalse Nock.Verb.instDecidableEqOutcome.decEq._proof_9
- Nock.Verb.instDecidableEqOutcome.decEq Nock.Verb.Outcome.timeout Nock.Verb.Outcome.timeout = isTrue ⋯
Instances For
Equations
A non-terminal halt is a crash.
Fuel-indexed evaluation distinguishing a crash from fuel exhaustion. Structurally identical to
run, so eval and run agree on values at the same fuel (eval_value_iff_run); the crash
branch turns run's conflated none into a positive crash.
Equations
- Nock.Verb.eval 0 x✝ = Nock.Verb.Outcome.timeout
- Nock.Verb.eval fuel.succ x✝ = match x✝.next with | some v' => Nock.Verb.eval fuel v' | none => x✝.haltOutcome
Instances For
Run a Nock program *[subject, formula], reporting value / crash / timeout.
Equations
- Nock.Verb.evalProgram fuel subject formula = Nock.Verb.eval fuel (Nock.Verb.program subject formula)
Instances For
Crash is stable one step on: if eval reports crash at fuel n, it reports crash at
n + 1. (The general "any larger fuel" form is eval_crash_mono_le.)