This PR allows `simp` to recognize and warn about simp lemmas that are likely looping in the current simp set. It does so automatically whenever simplification fails with the dreaded “max recursion depth” error fails, but it can be made to do it always with `set_option linter.loopingSimpArgs true`. This check is not on by default because it is somewhat costly, and can warn about simp calls that still happen to work. This closes #5111. In the end, this implemented much simpler logic than described there (and tried in the abandoned #8688; see that PR description for more background information), but it didn’t work as well as I thought. The current logic is: “Simplify the RHS of the simp theorem, complain if that fails”. It is a reasonable policy for a Lean project to say that all simp invocation should be so that this linter does not complain. Often it is just a matter of explicitly disabling some simp theorems from the default simp set, to make it clear and robust that in this call, we do not want them to trigger. But given that often such simp call happen to work, it’s too pedantic to impose it on everyone.
56 lines
1.5 KiB
Text
56 lines
1.5 KiB
Text
def f91 (n : Nat) : Option Nat :=
|
||
if n > 100
|
||
then pure (n - 10)
|
||
else f91 (n + 11) >>= f91
|
||
partial_fixpoint
|
||
|
||
section partial_correctness
|
||
|
||
-- #check f91.partial_correctness
|
||
|
||
theorem f91_partial_spec (n r : Nat) :
|
||
f91 n = some r → r = if n > 100 then n - 10 else 91 := by
|
||
apply f91.partial_correctness
|
||
intro f91 ih n r h
|
||
split at *
|
||
· simp_all
|
||
· simp only [Option.bind_eq_bind, Option.bind_eq_some_iff] at h
|
||
obtain ⟨r', hr1, hr2⟩ := h
|
||
replace hr1 := ih _ _ hr1
|
||
replace hr2 := ih _ _ hr2
|
||
clear ih
|
||
subst hr1
|
||
subst hr2
|
||
split
|
||
· simp; omega
|
||
· simp
|
||
|
||
end partial_correctness
|
||
|
||
section total_correctness
|
||
|
||
theorem f91_spec_high (n : Nat) (h : 100 < n) : f91 n = some (n - 10) := by
|
||
unfold f91; simp [*]
|
||
|
||
theorem f91_spec_low (n : Nat) (h₂ : n ≤ 100) : f91 n = some 91 := by
|
||
unfold f91
|
||
have : ¬ (100 < n) := by simp [*]
|
||
simp [*]
|
||
by_cases n < 90
|
||
· rw [f91_spec_low (n + 11) (by omega)]
|
||
simp only [Option.bind_some]
|
||
rw [f91_spec_low 91 (by omega)]
|
||
· rw [f91_spec_high (n + 11) (by omega)]
|
||
simp only [Nat.reduceSubDiff, Option.bind_some]
|
||
by_cases h : n = 100
|
||
· set_option linter.loopingSimpArgs false in
|
||
simp [*, f91]
|
||
· exact f91_spec_low (n + 1) (by omega)
|
||
|
||
theorem f91_spec (n : Nat) :
|
||
f91 n = some (if n ≤ 100 then 91 else n - 10) := by
|
||
by_cases h100 : n ≤ 100
|
||
· simp [f91_spec_low, *]
|
||
· simp [f91_spec_high, Nat.lt_of_not_le ‹_›, *]
|
||
|
||
end total_correctness
|