Modules #
A Module T is a closed, well-typed, normal ModuleExpression of type T, together with the
operations on such (application, projections, pairing) and the IsModule bridge from Lean types
to ModuleTypeReps. The underlying expression calculus lives in ModuleExpression.lean (and
the files it imports).
- expression : ModuleExpression
- typed : self.expression.HasType [] T
- normal : self.expression.NormalClosed
Instances For
Build a Module from a well-typed closed expression by normalising it.
Instances For
Equations
- GaudisCrypt.instCoeFunModuleArrForall = { coe := fun (f : GaudisCrypt.Module (T.arr U)) (x : GaudisCrypt.Module T) => (f.expression.app x.expression).toModule ⋯ }
Equations
- m.fst' = m.expression.fst.toModule ⋯
Instances For
Equations
- m.snd' = m.expression.snd.toModule ⋯
Instances For
Equations
- m1.pair' m2 = (m1.expression.pair m2.expression).toModule ⋯
Instances For
A module's expression is closed, so a substitution leaves it alone.
A module's expression is closed, so a renaming leaves it alone. (This is what a substitution
going under a binder does to it — liftSubst renames by Nat.succ — so normalising an application
of a curried module needs this as well as Module.substituteSimultaneously_expression.)
Pairing two modules pairs their expressions — no reduce left over, both being normal.
Reducing a pair componentwise: if the components reduce to the expressions of the modules
m1/m2, the pair reduces to the expression of their Module.pair'. Turns a reduce of a
whole record into the record of the reduced components, with no detour through termination —
normality of the result comes from the modules m1/m2. (Currently unused: moduleApply
used to peel X.apply_simp's record with it, but now normalises both sides with
reduce_simp instead.)
Instances For
Equations
Instances For
- moduleTypeRep : ModuleTypeRep
Instances
Equations
- GaudisCrypt.instIsModuleModule = { moduleTypeRep := t, isModule := ⋯ }
Instances For
Equations
- GaudisCrypt.Module.cast T m = ⋯ ▸ m
Instances For
Equations
- GaudisCrypt.Module.cast' T m = ⋯ ▸ m
Instances For
Equations
Instances For
Equations
- GaudisCrypt.instIsModuleArr M N = { moduleTypeRep := (GaudisCrypt.Module.moduleTypeRep M).arr (GaudisCrypt.Module.moduleTypeRep N), isModule := ⋯ }
Equations
Instances For
Equations
- GaudisCrypt.instIsModuleProc = { moduleTypeRep := GaudisCrypt.ModuleTypeRep.proc sig, isModule := ⋯ }
Equations
- m.app' m' = (m.expression.app m'.expression).toModule ⋯
Instances For
Simp set collecting the field accessors moduletype emits (X.f : X → Tᵢ, a chain of
Module.fst'/Module.snd').
A goal about a field of an abstract module — S : CommitmentScheme a parameter, not a literal
record — can only make progress by unfolding the accessor, and a tactic cannot know the accessor's
name. This set is how procApply reaches them.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Simplification procedure
Equations
- One or more equations did not get rendered due to their size.
Instances For
What is derivable about a field accessor acc : M → T of a module type, bundled into one
declaration.
The moduletype command emits one of these per field, as X.f.utilities, rather than a separate
declaration per fact — the facts are reached as X.f.utilities.accessorModule and so on. It is a
structure and not a class: there is nothing to synthesise, the command hands the value over by
name.
- proj : ModuleExpression → ModuleExpression
The projection
accimplements, as it acts onModuleExpressions (fun e => e.snd.fst, …). - accessorModule : Module.Arr M T
The accessor as a module of its own: a projection is a module morphism.
…and applying that module is the accessor.
- expression_eq (m : M) : (Module.cast T (acc m)).expression = (self.proj (Module.cast M m).expression).reduce
The accessor at the level of expressions: it is
proj, reduced. The.reduceis not removable —Module.expressionis always a reduct, andproj m.expressionneed not be normal.
Instances For
Equations
Instances For
Equations
- GaudisCrypt.instIsModuleProd M N = { moduleTypeRep := (GaudisCrypt.Module.moduleTypeRep M).prod (GaudisCrypt.Module.moduleTypeRep N), isModule := ⋯ }
Equations
Instances For
Canonical forms at procedure type: a closed normal expression of type .proc sig is
literally a .proc p node.
The procedure of a proc-typed module — the inverse of Module.proc. (Classical.choose
only escapes the Prop-to-data restriction; the witness is unique — see
Module.procedure_spec and Module.procedure_proc/Module.procedure_proc'.)
Equations
- One or more equations did not get rendered due to their size.
Instances For
Module.procedure is characterized by its defining equation (the witness of
proc_type_is_proc is unique by constructor injectivity).
Round-trip: wrapping a procedure as a module and extracting recovers it.
Module.procedure_proc with Module.proc folded — the form the generated apply_simp lemmas
actually produce. The unfolded statement above is filed under a discrimination key mentioning
ModuleExpression.toModule, so it never fires against a Module.proc on its own and every caller
had to unfold Module.proc alongside it. Both are @[simp], so whichever form a goal is in, one
of them matches.
A module's expression is well-typed in any context, not just the empty one — it is closed.
This is what lets moduletyping type an expression built from already-formed modules (whose
leaves are m.expression rather than a HasType constructor).
Equations
- GaudisCrypt.Module.const m = (⋯ ▸ m).expression.abs.toModule ⋯
Instances For
Equations
Instances For
Applying a procedure-with-holes to its callees #
The δ-rule ReductionStep.delta fires only on a literal tuple of .proc nodes
(HoleSigs.Instantiation.toModuleExpr). What one has in practice is a tuple of arbitrary module
expressions — the callees, as they were written — which merely reduce to such a tuple, each of
them to the .proc of a Module.procedure. reduce_pair_of bridges the two, peeling the tuple
component by component, and reduce_app_procWithHoles then takes the δ-step. Together they are
what procApply (GaudisCrypt/Language/Syntax2.lean) runs on the X.<f>.apply_simp goals the
module command emits.
A tuple of procedures is normal: it is built from .proc nodes and .unit alone.
Peeling one component of the callee tuple, at the level of ModuleExpression alone.
Stating this at the level of expressions, rather than with the instantiation still folded up, is
what makes it usable: in procApply the goal carries a written-out instantiation, so
HoleSigs.Instantiation.toModuleExpr computes and the right-hand side is an ordinary expression
pair. A lemma phrased in terms of Instantiation could not be applied there at all —
Instantiation (.cons sig holes) does not reduce while holes is a metavariable, and the
elaborator will not solve holes from a sibling argument first.
hc is discharged by moduleCallee, hrest by the next round of this same lemma.
The δ-step, on an argument that only reduces to a tuple of procedures: applying
Module.procWithHoles p to it is the procedure p with its holes instantiated. With no holes at
all Module.procWithHoles p is the constant function Module.proc p, and instantiating changes
nothing (ProcedureWithHoles.instantiate_empty) — so the statement covers that case too.