This PR adds `+grind` and `+try?` options to `exact?` and `apply?`
tactics.
## `+grind` option
When `+grind` is enabled, `grind` is used as a fallback discharger for
subgoals that `solve_by_elim` cannot close. The proof is wrapped in
`Grind.Marker` so suggestions display `(by grind)` instead of the
complex grind proof term.
Example:
```lean
axiom foo (x : Nat) : x < 37 → 5 < x → x.log2 < 6
/--
info: Try this:
[apply] exact foo x (by grind) (by grind)
-/
#guard_msgs in
example (x : Nat) (h₁ : x < 30) (h₂ : 8 < x) : x.log2 < 6 := by
exact? +grind
```
## `+try?` option
When `+try?` is enabled, `try?` is used as a fallback discharger for
subgoals. This is useful when subgoals require induction or other
strategies that `try?` can find but `solve_by_elim` and `grind` cannot.
Example:
```lean
inductive MyList (α : Type _) where
| nil : MyList α
| cons : α → MyList α → MyList α
axiom MyListProp : MyList α → Prop
@[grind .] axiom mylist_nil : MyListProp (MyList.nil : MyList α)
@[grind .] axiom mylist_cons : ∀ (x : α) (xs : MyList α), MyListProp xs → MyListProp (MyList.cons x xs)
axiom qux (xs : MyList α) (p : MyListProp xs) : MyListProp2 xs
/--
info: Try this:
[apply] exact qux xs (by try?)
-/
example (xs : MyList α) : MyListProp2 xs := by
exact? +try?
```
🤖 Prepared with Claude Code
---------
Co-authored-by: Claude <noreply@anthropic.com>
51 lines
1.6 KiB
Text
51 lines
1.6 KiB
Text
module
|
|
|
|
import Lean
|
|
|
|
open Lean Meta
|
|
|
|
-- without this, the catch below does not catch kernel errors
|
|
set_option Elab.async false
|
|
|
|
/--
|
|
info: Possible candidates for Init/Core.lean (these do not need to be added if they are irrelevant for verification):
|
|
gen_injective_theorems% MacroScopesView
|
|
gen_injective_theorems% ParserDescr
|
|
gen_injective_theorems% SourceInfo
|
|
gen_injective_theorems% TSyntax
|
|
gen_injective_theorems% Macro.Context
|
|
gen_injective_theorems% Macro.Exception
|
|
gen_injective_theorems% Macro.Methods
|
|
gen_injective_theorems% Syntax.Preresolved
|
|
gen_injective_theorems% Syntax.SepArray
|
|
gen_injective_theorems% Syntax.TSepArray
|
|
gen_injective_theorems% Try.Config
|
|
gen_injective_theorems% Parser.Tactic.DecideConfig
|
|
gen_injective_theorems% Parser.Tactic.LibrarySearchConfig
|
|
-/
|
|
#guard_msgs in
|
|
run_meta
|
|
let mut names := #[]
|
|
for (name, ci) in (← getEnv).constants do
|
|
let .inductInfo info := ci | continue
|
|
if info.isUnsafe then continue
|
|
if isClass (← getEnv) name then continue
|
|
let bad ← do
|
|
try
|
|
let env0 ← getEnv
|
|
mkInjectiveTheorems name
|
|
let env1 ← getEnv
|
|
if env1.constants.map₂.toArray.size > env0.constants.map₂.toArray.size then
|
|
pure true
|
|
else
|
|
pure false
|
|
catch _ =>
|
|
pure false
|
|
if bad then
|
|
names := names.push name
|
|
unless names.isEmpty do
|
|
names := names.qsort Name.lt
|
|
let mut msg := m!"Possible candidates for Init/Core.lean (these do not need to be added if they are irrelevant for verification):\n"
|
|
for n in names do
|
|
msg := msg ++ m!"gen_injective_theorems% {.ofConstName n}\n"
|
|
logInfo msg
|