@@ -90,42 +90,69 @@ def List.init : List α → List α
90
90
| [_] => []
91
91
| a::l => a::init l
92
92
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.
95
123
-/
96
124
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) :=
98
126
do let type := (← getConstInfo c).instantiateTypeLevelParams univs
99
127
let type' ← Meta.forallBoundedTelescope type (params.length) fun fvars ty => do
100
128
pure $ ty.replaceFVars fvars params.toArray
101
129
102
130
Meta.forallTelescope type' fun fvars ty => do
103
131
let idxs_inst := ty.getAppArgs.toList.drop params.length
104
132
let (bs, eqs, subst) := compactRelation fvars.toList (idxs.zip idxs_inst)
105
- let bs' := bs.filterMap id
106
133
let eqs ← eqs.mapM (λ⟨idx, inst⟩ => do
107
134
let ty ← idx.fvarId!.getType
108
135
let instTy ← inferType inst
109
136
let u := (←inferType ty).sortLevel!
110
137
if ←isDefEq ty instTy
111
138
then pure (mkApp3 (mkConst `Eq [u]) ty idx inst)
112
139
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
114
141
| [], [] => do
115
- pure (Sum.inr 0 , (mkConst `True))
116
- | _ , [] => do
142
+ pure (some 0 , (mkConst `True))
143
+ | bs' , [] => do
117
144
let t : Expr ← bs'.getLast!.fvarId!.getType
118
145
let l := (←inferType t).sortLevel!
119
146
if l == Level.zero then do
120
147
let r ← mkExistsList (List.init bs') t
121
- pure (Sum.inl bs'.getLast! , subst r)
148
+ pure (none , subst r)
122
149
else do
123
150
let r ← mkExistsList bs' (mkConst `True)
124
- pure (Sum.inr 0 , subst r)
125
- | _ , _ => do
151
+ pure (some 0 , subst r)
152
+ | bs' , _ => do
126
153
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)
129
156
130
157
/-- Splits the goal `n` times via `refine ⟨?_,?_⟩`, and then applies `constructor` to
131
158
close the resulting subgoals.
@@ -149,20 +176,20 @@ match n with
149
176
/-- Proves the left to right direction of a generated iff theorem.
150
177
`shape` is the output of a call to `constrToProp`.
151
178
-/
152
- def toCases (mvar : MVarId) (shape : List $ List (Option Expr) × (Expr ⊕ Nat) ) : MetaM Unit :=
179
+ def toCases (mvar : MVarId) (shape : List Shape ) : MetaM Unit :=
153
180
do
154
181
let ⟨h, mvar'⟩ ← mvar.intro1
155
182
let subgoals ← mvar'.cases h
156
183
let _ ← (shape.zip subgoals.toList).enum.mapM fun ⟨p, ⟨⟨shape, t⟩, subgoal⟩⟩ => do
157
184
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 )
159
186
let mvar'' ← select p (subgoals.size - 1 ) subgoal.mvarId
160
187
match t with
161
- | Sum.inl _ => do
188
+ | none => do
162
189
let v := vars.get! (shape.length - 1 )
163
190
let mv ← mvar''.existsi (List.init si)
164
191
mv.assign v
165
- | Sum.inr n => do
192
+ | some n => do
166
193
let mv ← mvar''.existsi si
167
194
splitThenConstructor mv (n - 1 )
168
195
pure ()
@@ -193,40 +220,39 @@ match n with
193
220
pure (mvar', fvar1::rest)
194
221
195
222
/--
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
197
224
result and continue with the tail of first list. Otherwise, wrap the first element of the second
198
225
list with `some` and continue with the tails of both lists. Return when either list is empty.
199
226
200
227
Example:
201
228
```
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)]
203
230
```
204
231
-/
205
- def listOptionMerge {α : Type _} {β : Type _} : List (Option α) → List β → List (Option β )
232
+ def listBoolMerge {α : Type _} : List Bool → List α → List (Option α )
206
233
| [], _ => []
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 :: _, [] => []
210
237
211
238
/-- Proves the right to left direction of a generated iff theorem.
212
- `s` is the output of a call to `constrToProp`.
213
239
-/
214
240
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) :
216
242
MetaM Unit := do
217
243
match s.length with
218
244
| 0 => do let _ ← mvar.cases h
219
245
pure ()
220
246
| (n + 1 ) => do
221
247
let subgoals ← nCasesSum n mvar h
222
248
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
224
250
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
227
253
let mvar'' ← mvar'.tryClear fvars.getLast!
228
254
pure ⟨mvar'', fvars⟩
229
- | Sum.inr (e + 1 ) => do
255
+ | some (e + 1 ) => do
230
256
let (mv', fvars) ← nCasesProd n mv h
231
257
let lastfv := fvars.getLast!
232
258
let (mv2, fvars') ← nCasesProd e mv' lastfv
@@ -240,11 +266,10 @@ def toInductive (mvar : MVarId) (cs : List Name)
240
266
) mv3
241
267
pure (mv4, fvars)
242
268
mvar'.withContext do
243
- let ctxt ← getLCtx
244
- let fvarIds := ctxt.getFVarIds.toList
269
+ let fvarIds := (←getLCtx).getFVarIds.toList
245
270
let gs := fvarIds.take gs.length
246
271
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
248
273
let args ← m.mapM (λa => match a with
249
274
| some v => pure $ mkFVar v
250
275
| none => mkFreshExprMVar none)
0 commit comments