fix: include let bindings when determining altParamNums for eliminators (#3505)
Else the `case` will now allow introducing all necessary variables. Induction principles with `let` in the types of the cases will be more common with #3432. This implementation no longer reduces the type as it goes, but really only counts manifest foralls and lets. I find this more sensible and predictable: If you have ``` theorem induction₂_symm {P : EReal → EReal → Prop} (symm : Symmetric P) … ``` then previously, writing ``` case symm => ``` would actually bring a fresh `x` and `y` and variable `h : P x y` into scope and produce a goal of `P y x`, because `Symmetric P` happens to be ``` def Symmetric := ∀ ⦃x y⦄, x ≺ y → y ≺ x ``` After this change, after `case symm =>` will leave `Symmetric P` as the goal. This gives more control to the author of the induction hypothesis about the actual goal of the cases. This shows up in mathlib in two places; fixes in https://github.com/leanprover-community/mathlib4/pull/11023. I consider these improvements.
This commit is contained in:
parent
17b8880983
commit
fa058ed228
2 changed files with 24 additions and 2 deletions
|
|
@ -37,6 +37,15 @@ structure ElimInfo where
|
|||
altsInfo : Array ElimAltInfo := #[]
|
||||
deriving Repr, Inhabited
|
||||
|
||||
|
||||
/-- Given the type `t` of an alternative, determines the number of parameters
|
||||
(.forall and .let)-bound, and whether the conclusion is a `motive`-application. -/
|
||||
def altArity (motive : Expr) (n : Nat) : Expr → Nat × Bool
|
||||
| .forallE _ _ b _ => altArity motive (n+1) b
|
||||
| .letE _ _ _ b _ => altArity motive (n+1) b
|
||||
| conclusion => (n, conclusion.getAppFn == motive)
|
||||
|
||||
|
||||
def getElimExprInfo (elimExpr : Expr) (baseDeclName? : Option Name := none) : MetaM ElimInfo := do
|
||||
let elimType ← inferType elimExpr
|
||||
trace[Elab.induction] "eliminator {indentExpr elimExpr}\nhas type{indentExpr elimType}"
|
||||
|
|
@ -64,8 +73,7 @@ def getElimExprInfo (elimExpr : Expr) (baseDeclName? : Option Name := none) : Me
|
|||
if x != motive && !targets.contains x then
|
||||
let xDecl ← x.fvarId!.getDecl
|
||||
if xDecl.binderInfo.isExplicit then
|
||||
let (numFields, provesMotive) ← forallTelescopeReducing xDecl.type fun args concl =>
|
||||
pure (args.size, concl.getAppFn == motive)
|
||||
let (numFields, provesMotive) := altArity motive 0 xDecl.type
|
||||
let name := xDecl.userName
|
||||
let declName? := do
|
||||
let base ← baseDeclName?
|
||||
|
|
|
|||
14
tests/lean/run/indUsingLet.lean
Normal file
14
tests/lean/run/indUsingLet.lean
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
theorem some_induction
|
||||
{motive : Nat → Prop}
|
||||
(zero : motive 0)
|
||||
(succ : forall n, 0 < n → let m := n - 1; motive m → motive n) :
|
||||
∀ n, motive n
|
||||
| 0 => zero
|
||||
| n+1 => succ (n+1) (Nat.zero_lt_succ n) (some_induction zero succ n)
|
||||
|
||||
|
||||
example (n : Nat) : n = n := by
|
||||
induction n using some_induction
|
||||
case zero => rfl
|
||||
case succ n _h _m _IH =>
|
||||
rfl
|
||||
Loading…
Add table
Reference in a new issue