feat: make sure cases and induction alternatives are processed using the order provided by the user
Motivation: improve the effectiveness of the `save` and `checkpoint` tactics.
This commit is contained in:
parent
822375aaff
commit
e6aee1e463
5 changed files with 66 additions and 10 deletions
|
|
@ -202,6 +202,39 @@ private def saveAltVarsInfo (altMVarId : MVarId) (altStx : Syntax) (fvarIds : Ar
|
|||
Term.addLocalVarInfo altVars[i] (mkFVar fvarId)
|
||||
i := i + 1
|
||||
|
||||
/--
|
||||
If `altsSyntax` is not empty we reorder `alts` using the order the alternatives have been provided
|
||||
in `altsSyntax`. Motivations:
|
||||
|
||||
1- It improves the effectiveness of the `checkpoint` and `save` tactics. Consider the following example:
|
||||
```lean
|
||||
example (h₁ : p ∨ q) (h₂ : p → x = 0) (h₃ : q → y = 0) : x * y = 0 := by
|
||||
cases h₁ with
|
||||
| inr h =>
|
||||
sleep 5000 -- sleeps for 5 seconds
|
||||
save
|
||||
have : y = 0 := h₃ h
|
||||
-- We can confortably work here
|
||||
| inl h => stop ...
|
||||
```
|
||||
If we do reorder, the `inl` alternative will be executed first. Moreover, as we type in the `inr` alternative,
|
||||
type errors will "swallow" the `inl` alternative and affect the tactic state at `save` making it ineffective.
|
||||
|
||||
2- The errors are produced in the same order the appear in the code above. This is not super important when using IDEs.
|
||||
-/
|
||||
def reorderAlts (alts : Array (Name × MVarId)) (altsSyntax : Array Syntax) : Array (Name × MVarId) := Id.run do
|
||||
if altsSyntax.isEmpty then
|
||||
return alts
|
||||
else
|
||||
let mut alts := alts
|
||||
let mut result := #[]
|
||||
for altStx in altsSyntax do
|
||||
let altName := getAltName altStx
|
||||
let some i := alts.findIdx? (·.1 == altName) | return result ++ alts
|
||||
result := result.push alts[i]
|
||||
alts := alts.eraseIdx i
|
||||
return result ++ alts
|
||||
|
||||
def evalAlts (elimInfo : ElimInfo) (alts : Array (Name × MVarId)) (optPreTac : Syntax) (altsSyntax : Array Syntax)
|
||||
(initialInfo : Info)
|
||||
(numEqs : Nat := 0) (numGeneralized : Nat := 0) (toClear : Array FVarId := #[]) : TacticM Unit := do
|
||||
|
|
@ -213,6 +246,7 @@ def evalAlts (elimInfo : ElimInfo) (alts : Array (Name × MVarId)) (optPreTac :
|
|||
else go
|
||||
where
|
||||
go := do
|
||||
let alts := reorderAlts alts altsSyntax
|
||||
let hasAlts := altsSyntax.size > 0
|
||||
let mut usedWildcard := false
|
||||
let mut subgoals := #[] -- when alternatives are not provided, we accumulate subgoals here
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
690.lean:4:12-4:17: warning: declaration uses 'sorry'
|
||||
690.lean:3:2-3:29: error: too many variable names provided at alternative 'step', #3 provided, but #2 expected
|
||||
690.lean:3:24-3:29: warning: declaration uses 'sorry'
|
||||
690.lean:9:12-9:17: warning: declaration uses 'sorry'
|
||||
690.lean:4:12-4:17: warning: declaration uses 'sorry'
|
||||
690.lean:8:34-8:39: warning: declaration uses 'sorry'
|
||||
690.lean:9:12-9:17: warning: declaration uses 'sorry'
|
||||
case step
|
||||
a b m✝ : Nat
|
||||
hStep : Nat.le a m✝
|
||||
ih : Nat.le a (m✝ + 1)
|
||||
⊢ Nat.le a (Nat.succ m✝ + 1)
|
||||
690.lean:14:12-14:17: warning: declaration uses 'sorry'
|
||||
690.lean:13:37-13:42: warning: declaration uses 'sorry'
|
||||
690.lean:14:12-14:17: warning: declaration uses 'sorry'
|
||||
case step
|
||||
a b x : Nat
|
||||
hStep : Nat.le a x
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
inductionErrors.lean:12:12-12:27: error: unsolved goals
|
||||
case upper.h
|
||||
q d : Nat
|
||||
⊢ q + Nat.succ d > q
|
||||
inductionErrors.lean:11:12-11:27: error: unsolved goals
|
||||
case lower.h
|
||||
p d : Nat
|
||||
⊢ p ≤ p + Nat.succ d
|
||||
inductionErrors.lean:12:12-12:27: error: unsolved goals
|
||||
case upper.h
|
||||
q d : Nat
|
||||
⊢ q + Nat.succ d > q
|
||||
inductionErrors.lean:16:19-16:26: error: unknown constant 'elimEx2'
|
||||
inductionErrors.lean:22:2-25:45: error: insufficient number of targets for 'elimEx'
|
||||
inductionErrors.lean:28:16-28:23: error: unexpected eliminator resulting type
|
||||
|
|
@ -27,9 +27,9 @@ inductionErrors.lean:50:2-50:16: error: alternative 'cons' is not needed
|
|||
inductionErrors.lean:55:2-55:16: error: alternative 'cons' is not needed
|
||||
inductionErrors.lean:60:2-60:40: error: invalid alternative name 'upper2'
|
||||
inductionErrors.lean:66:2-66:28: error: invalid occurrence of wildcard alternative, it must be the last alternative
|
||||
inductionErrors.lean:72:29-72:34: warning: declaration uses 'sorry'
|
||||
inductionErrors.lean:71:29-71:34: warning: declaration uses 'sorry'
|
||||
inductionErrors.lean:72:29-72:34: warning: declaration uses 'sorry'
|
||||
inductionErrors.lean:74:2-74:34: error: unused alternative
|
||||
inductionErrors.lean:79:29-79:34: warning: declaration uses 'sorry'
|
||||
inductionErrors.lean:78:29-78:34: warning: declaration uses 'sorry'
|
||||
inductionErrors.lean:79:29-79:34: warning: declaration uses 'sorry'
|
||||
inductionErrors.lean:80:2-80:53: error: unused alternative
|
||||
|
|
|
|||
|
|
@ -139,8 +139,8 @@ theorem ex15 (p q : Nat) : p ≤ q ∨ p > q := by
|
|||
| lower d => _
|
||||
| upper d => ?hupper
|
||||
{ apply Or.inl; apply Nat.le_refl }
|
||||
{ apply Or.inr; show q + d.succ > q; admit }
|
||||
{ apply Or.inl; show p ≤ p + d.succ; admit }
|
||||
{ apply Or.inr; show q + d.succ > q; admit }
|
||||
|
||||
theorem ex16 {p q : Prop} (h : p ∨ q) : q ∨ p := by
|
||||
induction h
|
||||
|
|
|
|||
|
|
@ -8,3 +8,25 @@ example (h₁ : x = y) (h₂ : y = z) : z = x := by
|
|||
trace "hello world"
|
||||
apply this.trans
|
||||
exact ‹y = x›
|
||||
|
||||
example (h₁ : p ∨ q) (h₂ : p → x = 0) (h₃ : q → y = 0) : x * y = 0 := by
|
||||
expensive_tactic
|
||||
save
|
||||
match h₁ with
|
||||
| .inr h =>
|
||||
expensive_tactic
|
||||
save
|
||||
have : y = 0 := h₃ h
|
||||
simp [*]
|
||||
| .inl h => stop done
|
||||
|
||||
example (h₁ : p ∨ q) (h₂ : p → x = 0) (h₃ : q → y = 0) : x * y = 0 := by
|
||||
expensive_tactic
|
||||
save
|
||||
cases h₁ with
|
||||
| inr h =>
|
||||
expensive_tactic
|
||||
save
|
||||
have : y = 0 := h₃ h
|
||||
simp [*]
|
||||
| inl h => stop done
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue