What the sequence expressions Guarded2Network builds over inbox mean.
Core/ComputableTLAPlus/Semantics/Interface.lean keeps the expression layer abstract: Eval is a
relation with no axioms about any particular operator, and the only sequence facts it carries are
value-level (seqAppend, isSeq). That is deliberate — Core's semantics has no business naming
TLA⁺'s Sequences module. But this pass compiles a receive into Head/Tail/Len calls over
inbox (Guarded2Network.head/.tail/.lenGt), so its refinement proof has to know that
Head(inbox) denotes the first element of what inbox holds — a fact about those expressions,
not about Eval in general.
So the laws live here, in a class the refinement theorems take instance-implicit, and the split
is: ExprSemantics says what a sequence value is, SeqBuiltins says what this pass's
sequence expressions evaluate to. A concrete TLA⁺ evaluator will satisfy both; nothing in
Core/ has to mention Head to state either.
Each law is an ↔ against the expression's shape rather than a one-directional evaluation rule,
because the proof needs both readings: forwards to compute the target's guard from the source's
channel contents, backwards to rule out a target step the source cannot match.
The meaning of Guarded2Network's own sequence expressions, on top of ExprSemantics's
value-level sequence vocabulary.
- evalHead {Ξ : ComputableTLAPlus.OperatorEnv} {Ω : ComputableTLAPlus.Model V} {M : ComputableTLAPlus.Memory V} {e : ComputablePlusCal.Expression} {τ : ComputableTLAPlus.Typ} {v : V} : ComputableTLAPlus.ExprSemantics.Eval Ξ Ω M (head τ e) v ↔ ∃ (s : V) (vs : List V), ComputableTLAPlus.ExprSemantics.Eval Ξ Ω M e s ∧ ComputableTLAPlus.ExprSemantics.isSeq s (v :: vs)
Head(e)denotes the first element of the sequenceedenotes — and denotes nothing when that sequence is empty, which is what makes an emptyinboxblock the guard rather than abort the branch. - evalTail {Ξ : ComputableTLAPlus.OperatorEnv} {Ω : ComputableTLAPlus.Model V} {M : ComputableTLAPlus.Memory V} {e : ComputablePlusCal.Expression} {τ : ComputableTLAPlus.Typ} {t : V} : ComputableTLAPlus.ExprSemantics.Eval Ξ Ω M (tail τ e) t ↔ ∃ (s : V) (v : V) (vs : List V), ComputableTLAPlus.ExprSemantics.Eval Ξ Ω M e s ∧ ComputableTLAPlus.ExprSemantics.isSeq s (v :: vs) ∧ ComputableTLAPlus.ExprSemantics.isSeq t vs
Tail(e)denotes the sequence of everything but that first element. - evalLenGt {Ξ : ComputableTLAPlus.OperatorEnv} {Ω : ComputableTLAPlus.Model V} {M : ComputableTLAPlus.Memory V} {e : ComputablePlusCal.Expression} {τ : ComputableTLAPlus.Typ} {n : ℕ} {s : V} {vs : List V} : ComputableTLAPlus.ExprSemantics.Eval Ξ Ω M e s → ComputableTLAPlus.ExprSemantics.isSeq s vs → ∃ (b : V), ComputableTLAPlus.ExprSemantics.Eval Ξ Ω M (lenGt τ e n) b ∧ ComputableTLAPlus.ExprSemantics.isBool b ∧ (b = ComputableTLAPlus.ExprSemantics.tru ↔ n < vs.length)
Len(e) > nis a boolean whenevereis a sequence, and isTRUEexactly when that sequence has more thannelements. Two clauses rather than one: the guards this pass emits areawaits, andStatement.aborting'sawaitcase distinguishes "evaluates to a non-boolean" (abort) from "evaluates to something other thanTRUE" (block), so a proof that the compiled guard never aborts needs the boolean-ness separately from the truth condition. - evalSeqNil {Ξ : ComputableTLAPlus.OperatorEnv} {Ω : ComputableTLAPlus.Model V} {M : ComputableTLAPlus.Memory V} {τ : ComputableTLAPlus.Typ} {s : V} : ComputableTLAPlus.ExprSemantics.Eval Ξ Ω M (ComputableTLAPlus.Expression.seq [] τ) s ↔ ComputableTLAPlus.ExprSemantics.isSeq s []
The empty-sequence literal
<<>>denotes the empty sequence. WhatGuarded2Network/PlusCal.lean'sinboxinitializer (.seq [] τ) contributes to the initial state, and so what the refinement invariant starts from.
Instances
The three laws at the one argument the pass ever passes them #
Every call site builds its sequence expression over the variable inbox, so each law arrives
with its inner Eval already determined by a memory lookup. Specialising once here keeps
ExprSemantics.evalVar and isSeq_inj out of the refinement proofs, which is otherwise the same
four lines at every use.
Head(inbox) denotes the first element inbox holds, and only that. Note the hypothesis has the
sequence non-empty: on an empty inbox the law gives no value at all, which is what makes the
compiled guard block rather than abort.
Tail(inbox) denotes the sequence of everything after that first element.
Len(inbox) > n is a boolean, and is TRUE exactly when inbox holds more than n
elements.