Coercion.applyComputable is the second of Core/TypedTLAPlus/Coercion.lean's two structural
recursions over TypedTLAPlus.Coercion, discharging against ComputableTLAPlus.Expression
instead of TypedTLAPlus.Expression. Needed because a receive's channel/reference coercion is
stored unapplied and survives past Typed2Computable's type change: Guarded2Network is the
first pass with a concrete ComputableTLAPlus.Expression (the built Head(inbox)/Tail(inbox)
expression) to discharge it against, so it can't reuse Coercion.apply (fixed at
TypedTLAPlus.Expr).
Mirrors Coercion.apply case-for-case, except choose's domain here is a required Expression α rather than Option (Expression α) — see Core/ComputableTLAPlus/Syntax.lean's module doc.
Checked TLA⁺ expressions at ComputableTLAPlus's output type — what Coercion.applyComputable
transforms.
Instances For
Applies a coercion to an already-built ComputableTLAPlus.Expression — see the module doc
above for why this can't reuse Coercion.apply. Registers every synthesized node at the coerced
expression's own span, for the reason spelled out on Coercion.apply.
Equations
- One or more equations did not get rendered due to their size.
- TypedTLAPlus.Coercion.id.applyComputable e = e
- (c₁.comp c₂).applyComputable e = c₂.applyComputable (c₁.applyComputable e)
Instances For
Coercion.applyComputable and free variables #
freeVars_applyComputable_subset — a coercion adds no free variable — lives here rather than next
to the semantics: it needs Coercion.applyComputable's induction principle, generated only in this
module. The small mem_freeVars_* unfoldings it uses are re-exported for the semantics to reuse.
TODO(locally-nameless): re-derive freeVars_applyComputable_subset against the de Bruijn
applyComputable/liftBound; parked with the semantics port.
A .fnCall at a .nat index reads only its head.
Field access reads only its subject.
A coercion adds no free variable: every binder applyComputable introduces refers to itself
by a .bound index, liftBound never touches a .free name, and every splice of e sits under
an operator (Len/DOMAIN/.fnCall/.recordAccess) that carries e's free variables through
unchanged. ExprSemantics.evalCoerce needs this to shrink a Coercion.FreshFor hypothesis onto a
sub-expression (.comp, .function).
The ⊆ reading of freeVars_applyComputable_subset.
Coercion.applyComputable and openVar #
applyComputable commutes with an openVar traversal: every binder it introduces refers to itself
by .bound, every splice of e under a binder carries a liftBound 1 that openVar at the
raised depth cancels (Expression.openVar_liftBound_one_comm), and every other node passes the
traversal through. ExprSemantics.evalCoerce's .set/.function cases need this: the built .fn/
.map' body opens with the binder's hint, and the opened term must read as applyComputable
of the opened argument so the coercion recursion applies.
mapVars (openVarLam x) k pushes through applyComputable: the depth-generalised statement,
proved by recursion on the coercion. openVar_applyComputable is the k = 0 reading.
Applying a coercion and then opening the enclosing binder is opening it inside the argument
first: openVar slides through applyComputable.
A coercion preserves local closedness. applyComputable introduces binders but every splice of
e under one carries a liftBound 1, so opening the enclosing binder slides through
(openVar_applyComputable) and lands on e, which a locally-closed e is fixed by — so the whole
term is fixed by openVar, hence locally closed (Expression.LC.of_openVar_eq).