Module expressions #
Everything about ModuleExpression.reduce that rests on confluence
(ModuleExpressionConfluence.lean) or on normalization
(ModuleExpressionNormalization.lean): reduce is idempotent, agrees on convertible terms,
computes a normal form of a well-typed term, and is a congruence for every constructor — plus
the reduce_simp tactic built out of those lemmas.
ModuleExpressionBasics.lean holds the part of the development that needs neither: the syntax
tree, typing, substitution, reduction, normal forms and the moduletyping/normalmodule
tactics. This file is the one downstream modules import.
Termination is invariant along equireducibility: each ReductionStep preserves it via
multiStepReduction_terminating, and refl/symm/trans closure is immediate.
Reduction preserves typing.
The reduct of a well-typed closed term is closed-normal.
The reduct of a well-typed closed term is closed-normal.
A normal term is its own reduct (normal terms are stuck).
Remaining reduce specification lemmas #
Congruence form for .pair: combines two independently-computed simplifications
reduce a = a' / reduce b = b' (however they were obtained — a'/b' need not
themselves be fully reduced) into one for the surrounding .pair. Proved directly via
convertible: pairL/pairR lift convertible_reduce through .pair on each side, and
reduce_convertible_iff turns the resulting convertible witness back into a reduce
equation.
Congruence form for .app, matching reduce_pair_cong.
One-sided congruences. reduce_pair_cong/reduce_app_cong replace both components, so
simplifying only one of them means proving reduce b = b' for the other by rfl, i.e. putting
reduce b there — a reduce around a component that had none. These leave the other component
exactly as it is. (The hypothesis reduce a = a' already forces a' to be reduce a, hence
reduce a' = a' by idempotence, which is what makes the untouched side go through.)
Congruence form for .abs, matching reduce_pair_cong/reduce_app_cong.
Stripping an inner reduce #
reduce only cares about its argument up to convertibility, so a subterm that is already a
reduce can be replaced by what it reduces (reduce_idempotent on both sides of the matching
_cong lemma). This is what makes the .reduces that toModule leaves behind disappear when a
composite expression is reduced — the moduleApply tactic (GaudisCrypt/Language/Syntax2.lean)
uses all six of them to bring the two sides of an X.apply_simp goal into the same shape.
Tactics #
reduce_simp #
reduceSimpHead takes a goal of the form
reduce M = reduce ?m or reduce M = ?m and solves it by instantiating the rhs as reduce M'
where M' is the result of applying a single reduction step.
Rules of the form reduce X = reduce Y or reduce X = Y
or convertible X Y or MultiStepReduction X Y or Step X Y
in the context are also used as reduction steps.
It fails when no step applies. In particular a term that is already normal is not its business:
it never uses reduce_of_normal, so it neither succeeds without reducing nor leaves a reduce
around a component it did not touch. Collapsing the reduce of a normal term is the second rule
of reduceSimpProcImpl instead.
A plain TacticM function, not a syntax/macro_rules pair, so it adds nothing to the tactic
grammar. The head-step alternatives stay a first | … quotation run via evalTactic; the
congruence rules — the only recursive part — are tried in order by hand, each followed by a
recursive call, with backtracking between them. Invoke it from a proof with run_tac.
Fully normalize reduce m subterms — one reduction step at a time via reduceSimpHead,
then the reduce collapsed via reduce_of_normal (see reduceSimpProcImpl) — repeatedly,
including inside freshly-exposed nested reduces (handled by simp's own subterm traversal,
not by this tactic). Lenient per subterm — whatever it can't reduce is left as it is — but,
like simp, it fails when that is every subterm and the goal comes back unchanged. Closes
the goal outright if it simplifies all the way to True.
substitute and friends are in the simp set because reduce_beta's result is
reduce (body.substitute arg), with substitute a structurally recursive def that no
reduceSimpHead branch matches on: unfolding it is what turns that result back into a
constructor tree the next step can work on.
The tactic keyword reduce_simp is this function; it stays a keyword because proofs are
written with it by hand. Tactics that want it as a step call reduceSimp directly rather
than going back through the grammar.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Fully normalize reduce m subterms — one reduction step at a time via reduceSimpHead,
then the reduce collapsed via reduce_of_normal (see reduceSimpProcImpl) — repeatedly,
including inside freshly-exposed nested reduces (handled by simp's own subterm traversal,
not by this tactic). Lenient per subterm — whatever it can't reduce is left as it is — but,
like simp, it fails when that is every subterm and the goal comes back unchanged. Closes
the goal outright if it simplifies all the way to True.
substitute and friends are in the simp set because reduce_beta's result is
reduce (body.substitute arg), with substitute a structurally recursive def that no
reduceSimpHead branch matches on: unfolding it is what turns that result back into a
constructor tree the next step can work on.
The tactic keyword reduce_simp is this function; it stays a keyword because proofs are
written with it by hand. Tactics that want it as a step call reduceSimp directly rather
than going back through the grammar.
Equations
- GaudisCrypt.tacticReduce_simp = Lean.ParserDescr.node `GaudisCrypt.tacticReduce_simp 1024 (Lean.ParserDescr.nonReservedSymbol "reduce_simp" false)