Documentation

GaudisCrypt.Language.ModuleExpressions

Module expressions #

The raw calculus underlying modules: ModuleTypeRep (the types), the untyped syntax tree ModuleExpression with extrinsic typing (ModuleExpression.HasType), de Bruijn renaming/substitution, call-by-value reduction with its normal forms, and the deciding tactics moduletyping, normalmodule and reduce_simp.

Modules.lean builds Module T — a closed, well-typed, normal expression — on top of this.

Possible types of modules.

Instances For

    The right-nested product type of a hole signature (native UM copy of the TypedModules definition; namespace-scoped under GaudisCrypt to avoid clashing with TypedModules's while both coexist).

    Equations
    Instances For

      Untyped module expressions: the raw syntax tree of the module calculus, with no context/type indices. Well-typedness is captured extrinsically by the predicate ModuleExpression.HasType. Variables are de Bruijn indices (Nat); abs carries no domain annotation (the domain is recovered by HasType).

      Instances For

        ModuleExpression.HasType m Δ T holds when the untyped expression m is well-typed in module context Δ with type T. This is the extrinsic counterpart of the indices of TypedModules.ModuleExpression: every TypedModules.ModuleExpression Δ T erases (via TypedModules.ModuleExpression.erase) to an m with HasType m Δ T, and conversely.

        Instances For

          De Bruijn renaming and substitution on the untyped tree #

          The untyped analogues of TypedModules.ModuleExpression.rename/substitute: since there are no type indices, a renaming is a plain Nat → Nat and a substitution a Nat → ModuleExpression. These are permanent. Their agreement with the intrinsic versions under erase is recorded by the transitional erase_rename/erase_substitute* lemmas below.

          Lift a de Bruijn renaming under one binder: index 0 is fixed, n+1 ↦ ρ n + 1. Untyped analogue of liftRenaming.

          Equations
          Instances For

            Lift a substitution under one binder: index 0 ↦ var 0; n+1 ↦ the weakening of σ n. Untyped analogue of liftSubstitution.

            Equations
            Instances For

              Apply a simultaneous substitution to every variable, going under binders with liftSubst. Untyped analogue of substituteSimultaneously.

              Equations
              Instances For

                Single-variable substitution map: 0 ↦ arg, n+1 ↦ var n. Untyped analogue of variableSubstitution.

                Equations
                Instances For

                  Single-variable de Bruijn substitution: replace index 0 in body by arg.

                  Equations
                  Instances For

                    Reduction on the untyped tree, and type preservation #

                    ReductionStep mirrors the intrinsic one but on raw syntax; the payoff is HasType.preservation — what intrinsic typing gave for free must now be proved. All permanent.

                    The untyped tuple of procedures corresponding to an instantiation (untyped analogue of HoleSigs.Instantiation.toModuleTuple).

                    Equations
                    Instances For

                      Non-deterministic single-step reduction on untyped module expressions.

                      Instances For

                        A de Bruijn renaming ρ maps context Δ into Γ if every Δ-index has a Γ-index of the same type sitting at the renamed position.

                        Equations
                        Instances For

                          Weakening: prepending a binder is the renaming Nat.succ.

                          theorem GaudisCrypt.ModuleExpression.HasType.IsRenaming.lift {Δ Γ : ModuleContext} {A : ModuleTypeRep} {ρ : ℕ → ℕ} (h : IsRenaming Δ Γ ρ) :
                          IsRenaming (A :: Δ) (A :: Γ) (liftRen ρ)

                          A context renaming lifts under one binder to liftRen ρ.

                          Renaming preserves typing along a context renaming.

                          A substitution σ maps Δ into Γ if it sends every Δ-index to a Γ-typed term.

                          Equations
                          Instances For

                            A well-typed substitution lifts under one binder to liftSubst σ.

                            Simultaneous substitution preserves typing along a well-typed substitution.

                            theorem GaudisCrypt.ModuleExpression.HasType.substitute [ProgramSpec] {Δ : List ModuleTypeRep} {u t : ModuleTypeRep} {body arg : ModuleExpression} (hb : body.HasType (u :: Δ) t) (ha : arg.HasType Δ u) :
                            (body.substitute arg).HasType Δ t

                            Single-variable substitution preserves typing (the β-substitution lemma).

                            A term only mentions the variables its context declares, so a substitution that is the identity on those leaves it alone — whatever it does to the indices beyond Δ. For a closed term (Δ = []) the hypothesis is vacuous: Module.substituteSimultaneously_expression.

                            The same for a renaming: a term only mentions the variables its context declares, so a renaming that is the identity on those leaves it alone. For a closed term (Δ = []) the hypothesis is vacuous: Module.rename_expression.

                            Type preservation (subject reduction): reduction preserves the typing judgment. This is the extrinsic replacement for what the intrinsic TypedModules.ModuleExpression guaranteed by construction.

                            Normal forms on the untyped tree #

                            Untyped analogues of IsProcHoles/IsProcTuple/Normal/Neutral/NormalClosed. Permanent; mirror the intrinsic versions structurally.

                            m is a right-nested tuple of hole-free procedures (.unit, or .pair (.proc _) rest with IsProcTuple rest) — the ground arguments a procedure-with-holes accepts.

                            Equations
                            Instances For
                              @[implicit_reducible]
                              Equations

                              Beta-normal form: no redex anywhere.

                              Instances For

                                Neutral form: no outermost redex — the head is a variable, or a procedure-with-holes applied to a normal non-proc-tuple (so the δ-rule is stuck).

                                Instances For

                                  Normal form of a closed term. Neutral terms cannot occur closed (they need a free variable), so there are fewer cases than Normal; the abs body is still general Normal (it lives under one binder).

                                  Instances For

                                    Embedding into Metatheory.STLCext #

                                    Shape predicates for call-by-value reduction (untyped analogues) #

                                    Typing is preserved along multi-step reduction.

                                    m terminates: it multi-step reduces to some normal form.

                                    Equations
                                    Instances For

                                      Convertibility: the equivalence relation generated by ReductionStep, i.e. its reflexive, symmetric, transitive closure.

                                      Equations
                                      Instances For

                                        β-normal form: a chosen normal form reachable from m when it terminates, else unit.

                                        Equations
                                        Instances For

                                          Multi-step reduction refines convertibility.

                                          Termination is invariant along equireducibility: each ReductionStep preserves it via multiStepReduction_terminating, and refl/symm/trans closure is immediate.

                                          reduce m is always convertible to m (a reduct if terminating, a class rep otherwise).

                                          Reduction preserves typing.

                                          Progress for well-typed (possibly open) terms: a non-normal well-typed term reduces.

                                          A normal well-typed closed term is closed-normal.

                                          The reduct of a well-typed closed term is closed-normal.

                                          The reduct of a well-typed closed term is closed-normal.

                                          @[simp]

                                          A normal term is its own reduct (normal terms are stuck).

                                          Misc #

                                          app is a congruence for multi-step reduction.

                                          pair is a congruence for multi-step reduction.

                                          A pair of stuck expressions is stuck: pair can only step via pairL/pairR.

                                          Remaining reduce specification lemmas #

                                          theorem GaudisCrypt.ModuleExpression.reduce_pair_cong [ProgramSpec] {a a' b b' : ModuleExpression} (ha : a.reduce = a') (hb : b.reduce = b') :
                                          (a.pair b).reduce = (a'.pair b').reduce

                                          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.

                                          theorem GaudisCrypt.ModuleExpression.reduce_app_cong [ProgramSpec] {a a' b b' : ModuleExpression} (ha : a.reduce = a') (hb : b.reduce = b') :
                                          (a.app b).reduce = (a'.app b').reduce

                                          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.)

                                          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 module_apply 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.

                                          A well-typed closed normal term of product type is a pair.

                                          Tactics #

                                          moduletyping #

                                          Syntax-directed closer for ModuleExpression.HasType m Δ T: peels off the HasType constructor matching m's head, leaves whatever it cannot close (e.g. an unprovable .var bound) as an open goal. See moduletyping! for a variant that fails loudly instead.

                                          Equations
                                          Instances For

                                            moduletyping, but fails loudly instead of leaving unclosed goals open. Not fail-fast: it still runs the core script to completion (closing everything it can) before reporting, one "Cannot show ‹original goal›: ‹reason›" line per leftover goal, with the reason coming from describeStuckModuleTypingGoal.

                                            Equations
                                            Instances For

                                              normalmodule #

                                              One step of normalmodule's core script, factored out so normalmodule can require it to fire at least once (see below) while still repeating it leniently afterwards.

                                              Equations
                                              Instances For

                                                Syntax-directed closer for Normal m / Neutral m: peels the constructor matching m's head, disambiguating .app's two constructors by checking whether the function side is a literal .procHoles node, and leaves whatever it cannot close open. Fails outright if it cannot make even one step of progress (e.g. Neutral (.pair _ _), which no constructor can ever produce) rather than silently no-op'ing. See normalmodule! for a variant that fails loudly with a diagnosed reason on every unclosed goal, not just a wholly-stuck one.

                                                Equations
                                                Instances For

                                                  normalmodule, but fails loudly instead of leaving unclosed goals open. Not fail-fast: it still runs the core script to completion (closing everything it can) before reporting, one "Cannot show ‹original goal›: ‹reason›" line per leftover goal, with the reason coming from describeStuckNormalModuleGoal.

                                                  Equations
                                                  Instances For

                                                    reduce_simp #

                                                    Fully normalize reduce m subterms — one reduction step at a time via reduce_simp_head, 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 reduce_simp_head branch matches on: unfolding it is what turns that result back into a constructor tree the next step can work on.

                                                    Equations
                                                    Instances For