Skip to content

Commit c8ba7d0

Browse files
committed
feat: port a basic version of applyAssumption (#708)
This is the most boring version of `apply_assumption` that does not symmetry and so on, but I think it might be better to include this into mathlib4 now, maybe it solves some porting issues already. The other features are probably less trivial.
1 parent 04e92ad commit c8ba7d0

File tree

3 files changed

+45
-11
lines changed

3 files changed

+45
-11
lines changed

Mathlib/Mathport/Syntax.lean

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,8 +247,6 @@ namespace Tactic
247247
/- S -/ syntax (name := revertTargetDeps) "revert_target_deps" : tactic
248248
/- E -/ syntax (name := clearValue) "clear_value" (ppSpace colGt ident)* : tactic
249249

250-
/- M -/ syntax (name := applyAssumption) "apply_assumption" : tactic
251-
252250
/- S -/ syntax (name := hint) "hint" : tactic
253251

254252
/- M -/ syntax (name := congrM) "congrm " term : tactic

Mathlib/Tactic/SolveByElim.lean

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,9 @@ a second time with different values of the metavariables.
6767
See https://github.com/leanprover-community/mathlib/issues/2269
6868
-/
6969
def mkAssumptionSet (noDflt : Bool) (hs : List (TSyntax `term)) :
70-
MetaM (List (TermElabM Expr) × TermElabM (List Expr)) :=
71-
do
70+
MetaM (List (TermElabM Expr) × TermElabM (List Expr)) := do
71+
let hs := if noDflt then hs else [← `(rfl), ← `(trivial), ← `(congrFun), ← `(congrArg)] ++ hs
7272
let hs := hs.map (λ s => Elab.Term.elabTerm s.raw none)
73-
let hs := if noDflt then hs else
74-
([← `(rfl), ← `(trivial), ← `(congrFun), ← `(congrArg)].map
75-
(λ s => Elab.Term.elabTerm s.raw none)) ++ hs
7673
let locals : TermElabM (List Expr) := if noDflt then pure [] else pure (← getLocalHyps).toList
7774
return (hs, locals)
7875

@@ -81,6 +78,11 @@ def exceptEmoji : Except ε α → String
8178
| .error _ => crossEmoji
8279
| .ok _ => checkEmoji
8380

81+
/-- Elaborate the context and the list of lemmas -/
82+
def elabContextLemmas (lemmas : List (TermElabM Expr)) (ctx : TermElabM (List Expr)) :
83+
MetaM (List Expr) := Elab.Term.TermElabM.run' do
84+
pure ((← lemmas.mapM id) ++ (← ctx))
85+
8486
/-- Attempt to solve the given metavariable by repeating applying a list of facts. -/
8587
def solveByElimAux (lemmas : List (TermElabM Expr)) (ctx : TermElabM (List Expr)) (n : Nat) :
8688
TacticM Unit := Tactic.done <|> match n with
@@ -92,10 +94,7 @@ def solveByElimAux (lemmas : List (TermElabM Expr)) (ctx : TermElabM (List Expr)
9294
-- the `do` block below runs, potentially unifying mvars in the goal.
9395
(return m!"{exceptEmoji ·} working on: {← addMessageContextFull goal}")
9496
do
95-
let es ← Elab.Term.TermElabM.run' do
96-
let ctx' ← ctx
97-
let lemmas' ← lemmas.mapM id
98-
pure (lemmas' ++ ctx')
97+
let es ← elabContextLemmas lemmas ctx
9998

10099
-- We attempt to find an expression which can be applied,
101100
-- and for which all resulting sub-goals can be discharged using `solveByElim n`.
@@ -158,3 +157,29 @@ syntax (name := solveByElim) "solve_by_elim" "*"? (config)? (&" only")? (simpArg
158157
elab_rules : tactic | `(tactic| solve_by_elim $[only%$o]? $[[$[$t:term],*]]?) => do
159158
let es := (t.getD #[]).toList
160159
solveByElimImpl o.isSome es 6 (← getMainGoal)
160+
161+
/--
162+
`apply_assumption` looks for an assumption of the form `... → ∀ _, ... → head`
163+
where `head` matches the current goal.
164+
165+
[todo] not yet implemented:
166+
If this fails, `apply_assumption` will call `symmetry` and try again.
167+
168+
[todo] not yet implemented:
169+
If this also fails, `apply_assumption` will call `exfalso` and try again,
170+
so that if there is an assumption of the form `P → ¬ Q`, the new tactic state
171+
will have two goals, `P` and `Q`.
172+
173+
[todo] not yet implemented:
174+
Optional arguments:
175+
- `lemmas`: a list of expressions to apply, instead of the local constants
176+
- `tac`: a tactic to run on each subgoal after applying an assumption; if
177+
this tactic fails, the corresponding assumption will be rejected and
178+
the next one will be attempted.
179+
-/
180+
syntax (name := applyAssumption) "apply_assumption" : tactic
181+
182+
elab_rules : tactic | `(tactic| apply_assumption) => withMainContext do
183+
let ctx := (← getLocalHyps).toList
184+
let lemmas := [← `(rfl), ← `(trivial), ← `(congrArg)].map (λ s => Elab.Term.elabTerm s.raw none)
185+
(← elabContextLemmas lemmas (pure ctx)).firstM fun e => (liftMetaTactic (Lean.MVarId.apply · e))

test/SolveByElim.lean

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,14 @@ example (P₁ P₂ : α → Prop) (f : ∀ (a: α), P₁ a → P₂ a → β)
5757
-- TODO this works in mathlib3 but not here yet, for some reason.
5858
-- example {α : Type} {a b : α → Prop} (h₀ : b = a) (y : α) : a y = b y :=
5959
-- by solve_by_elim
60+
61+
section apply_assumption
62+
63+
example {a b : Type} (h₀ : a → b) (h₁ : a) : b := by
64+
apply_assumption
65+
apply_assumption
66+
67+
example {α : Type} {p : α → Prop} (h₀ : ∀ x, p x) (y : α) : p y := by
68+
apply_assumption
69+
70+
end apply_assumption

0 commit comments

Comments
 (0)