Skip to content

Commit 35aa345

Browse files
committed
refactor: docs and simplifications for mk_iff (#595)
Some cleanup and documentation for #561.
1 parent e0335f9 commit 35aa345

File tree

2 files changed

+56
-32
lines changed

2 files changed

+56
-32
lines changed

Mathlib/Tactic/MkIffOfInductiveProp.lean

Lines changed: 56 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -90,42 +90,69 @@ def List.init : List α → List α
9090
| [_] => []
9191
| a::l => a::init l
9292

93-
/-- Converts an inductive constructor `c` into an intermediate representation that
94-
will later be mapped into a proposition.
93+
/-- Auxiliary data associated with a single constructor of an inductive declaration.
94+
-/
95+
structure Shape : Type where
96+
/-- For each forall-bound variable in the type of the constructor, minus
97+
the "params" that apply to the entire inductive type, this list contains `true`
98+
if that variable has been kept after `compactRelation`.
99+
100+
For example, `List.Chain.nil` has type
101+
```lean
102+
∀ {α : Type u_1} {R : α → α → Prop} {a : α}, List.Chain R a []`
103+
```
104+
and the first two variables `α` and `R` are "params", while the `a : α` gets
105+
eliminated in a `compactRelation`, so `variablesKept = [false].
106+
107+
`List.Chain.cons` has type
108+
```lean
109+
∀ {α : Type u_1} {R : α → α → Prop} {a b : α} {l : List α},
110+
R a b → List.Chain R b l → List.Chain R a (b :: l)
111+
```
112+
and the `a : α` gets eliminated, so `compactRelation = [false,true,true,true,true]`.
113+
-/
114+
variablesKept : List Bool
115+
116+
/-- The number of equalities, or `none` in the case when we've reduced something
117+
of the form `p ∧ True` to just `p`.
118+
-/
119+
neqs : Option Nat
120+
121+
/-- Converts an inductive constructor `c` into a `Shape` that will be used later in
122+
while proving the iff theorem, and a proposition representing the constructor.
95123
-/
96124
def constrToProp (univs : List Level) (params : List Expr) (idxs : List Expr) (c : Name) :
97-
MetaM ((List (Option Expr) × (Expr ⊕ Nat)) × Expr) :=
125+
MetaM (Shape × Expr) :=
98126
do let type := (← getConstInfo c).instantiateTypeLevelParams univs
99127
let type' ← Meta.forallBoundedTelescope type (params.length) fun fvars ty => do
100128
pure $ ty.replaceFVars fvars params.toArray
101129

102130
Meta.forallTelescope type' fun fvars ty => do
103131
let idxs_inst := ty.getAppArgs.toList.drop params.length
104132
let (bs, eqs, subst) := compactRelation fvars.toList (idxs.zip idxs_inst)
105-
let bs' := bs.filterMap id
106133
let eqs ← eqs.mapM (λ⟨idx, inst⟩ => do
107134
let ty ← idx.fvarId!.getType
108135
let instTy ← inferType inst
109136
let u := (←inferType ty).sortLevel!
110137
if ←isDefEq ty instTy
111138
then pure (mkApp3 (mkConst `Eq [u]) ty idx inst)
112139
else pure (mkApp4 (mkConst `HEq [u]) ty idx instTy inst))
113-
let (n, r) ← match bs', eqs with
140+
let (n, r) ← match bs.filterMap id, eqs with
114141
| [], [] => do
115-
pure (Sum.inr 0, (mkConst `True))
116-
| _, [] => do
142+
pure (some 0, (mkConst `True))
143+
| bs', [] => do
117144
let t : Expr ← bs'.getLast!.fvarId!.getType
118145
let l := (←inferType t).sortLevel!
119146
if l == Level.zero then do
120147
let r ← mkExistsList (List.init bs') t
121-
pure (Sum.inl bs'.getLast!, subst r)
148+
pure (none, subst r)
122149
else do
123150
let r ← mkExistsList bs' (mkConst `True)
124-
pure (Sum.inr 0, subst r)
125-
| _, _ => do
151+
pure (some 0, subst r)
152+
| bs', _ => do
126153
let r ← mkExistsList bs' (mkAndList eqs)
127-
pure (Sum.inr eqs.length, subst r)
128-
pure ((bs, n), r)
154+
pure (some eqs.length, subst r)
155+
pure (⟨bs.map Option.isSome, n, r)
129156

130157
/-- Splits the goal `n` times via `refine ⟨?_,?_⟩`, and then applies `constructor` to
131158
close the resulting subgoals.
@@ -149,20 +176,20 @@ match n with
149176
/-- Proves the left to right direction of a generated iff theorem.
150177
`shape` is the output of a call to `constrToProp`.
151178
-/
152-
def toCases (mvar : MVarId) (shape : List $ List (Option Expr) × (Expr ⊕ Nat)) : MetaM Unit :=
179+
def toCases (mvar : MVarId) (shape : List Shape) : MetaM Unit :=
153180
do
154181
let ⟨h, mvar'⟩ ← mvar.intro1
155182
let subgoals ← mvar'.cases h
156183
let _ ← (shape.zip subgoals.toList).enum.mapM fun ⟨p, ⟨⟨shape, t⟩, subgoal⟩⟩ => do
157184
let vars := subgoal.fields
158-
let si := (shape.zip vars.toList).filterMap (λ ⟨c,v⟩ => c >>= λ _ => some v)
185+
let si := (shape.zip vars.toList).filterMap (λ ⟨c,v⟩ => if c then some v else none)
159186
let mvar'' ← select p (subgoals.size - 1) subgoal.mvarId
160187
match t with
161-
| Sum.inl _ => do
188+
| none => do
162189
let v := vars.get! (shape.length - 1)
163190
let mv ← mvar''.existsi (List.init si)
164191
mv.assign v
165-
| Sum.inr n => do
192+
| some n => do
166193
let mv ← mvar''.existsi si
167194
splitThenConstructor mv (n - 1)
168195
pure ()
@@ -193,40 +220,39 @@ match n with
193220
pure (mvar', fvar1::rest)
194221

195222
/--
196-
Iterate over two lists, if the first element of the first list is `none`, insert `none` into the
223+
Iterate over two lists, if the first element of the first list is `false`, insert `none` into the
197224
result and continue with the tail of first list. Otherwise, wrap the first element of the second
198225
list with `some` and continue with the tails of both lists. Return when either list is empty.
199226
200227
Example:
201228
```
202-
listOptionMerge [none, some (), none, some ()] [0, 1, 2, 3, 4] = [none, (some 0), none, (some 1)]
229+
listBoolMerge [false, true, false, true] [0, 1, 2, 3, 4] = [none, (some 0), none, (some 1)]
203230
```
204231
-/
205-
def listOptionMerge {α : Type _} {β : Type _} : List (Option α) → List β → List (Option β)
232+
def listBoolMerge {α : Type _} : List Bool → List α → List (Option α)
206233
| [], _ => []
207-
| none :: xs, ys => none :: listOptionMerge xs ys
208-
| some _ :: xs, y :: ys => some y :: listOptionMerge xs ys
209-
| some _ :: _, [] => []
234+
| false :: xs, ys => none :: listBoolMerge xs ys
235+
| true :: xs, y :: ys => some y :: listBoolMerge xs ys
236+
| true :: _, [] => []
210237

211238
/-- Proves the right to left direction of a generated iff theorem.
212-
`s` is the output of a call to `constrToProp`.
213239
-/
214240
def toInductive (mvar : MVarId) (cs : List Name)
215-
(gs : List Expr) (s : List (List (Option Expr) × (Expr ⊕ Nat))) (h : FVarId) :
241+
(gs : List Expr) (s : List Shape) (h : FVarId) :
216242
MetaM Unit := do
217243
match s.length with
218244
| 0 => do let _ ← mvar.cases h
219245
pure ()
220246
| (n + 1) => do
221247
let subgoals ← nCasesSum n mvar h
222248
let _ ← (cs.zip (subgoals.zip s)).mapM $ λ⟨constr_name, ⟨h, mv⟩, bs, e⟩ => do
223-
let n := (bs.filterMap id).length
249+
let n := (bs.filter id).length
224250
let (mvar', _fvars) ← match e with
225-
| Sum.inl _ => nCasesProd (n-1) mv h
226-
| Sum.inr 0 => do let ⟨mvar', fvars⟩ ← nCasesProd n mv h
251+
| none => nCasesProd (n-1) mv h
252+
| some 0 => do let ⟨mvar', fvars⟩ ← nCasesProd n mv h
227253
let mvar'' ← mvar'.tryClear fvars.getLast!
228254
pure ⟨mvar'', fvars⟩
229-
| Sum.inr (e + 1) => do
255+
| some (e + 1) => do
230256
let (mv', fvars) ← nCasesProd n mv h
231257
let lastfv := fvars.getLast!
232258
let (mv2, fvars') ← nCasesProd e mv' lastfv
@@ -240,11 +266,10 @@ def toInductive (mvar : MVarId) (cs : List Name)
240266
) mv3
241267
pure (mv4, fvars)
242268
mvar'.withContext do
243-
let ctxt ← getLCtx
244-
let fvarIds := ctxt.getFVarIds.toList
269+
let fvarIds := (←getLCtx).getFVarIds.toList
245270
let gs := fvarIds.take gs.length
246271
let hs := (fvarIds.reverse.take n).reverse
247-
let m := gs.map some ++ listOptionMerge bs hs
272+
let m := gs.map some ++ listBoolMerge bs hs
248273
let args ← m.mapM (λa => match a with
249274
| some v => pure $ mkFVar v
250275
| none => mkFreshExprMVar none)

test/MkIffOfInductive.lean

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import Mathlib.Tactic.MkIffOfInductiveProp
33
import Mathlib.Data.List.Perm
44

55
mk_iff_of_inductive_prop List.Chain test.chain_iff
6-
76
example {α : Type _} (R : α → α → Prop) (a : α) (al : List α) :
87
List.Chain R a al ↔
98
al = List.nil ∨ ∃ (b : α) (l : List α), R a b ∧ List.Chain R b l ∧ al = b :: l :=

0 commit comments

Comments
 (0)