Zulip Chat Archive
Stream: lean4
Topic: Tactic writing
Alice Laroche (Feb 09 2022 at 14:50):
Hello,
I want both state to be equal, but it doesn't happen.
I need to do it through MetaM because other goal will be closed too in future code
import Lean.Meta
import Lean.Elab
import Lean.Meta.Tactic.Rewrite
open Lean Meta Elab Tactic
open Lean.Elab.Term
elab "myTactic " : tactic => do
liftMetaTactic fun mvarId => do
let (h, mvarId) <- intro1P mvarId
let goals <- apply mvarId (mkApp (mkConst ``Or.elim) (mkFVar h))
return goals
theorem test {p: Prop} : (p ∨ p) -> p := by intro h
apply Or.elim h
trace_state
theorem test' {p: Prop} : (p ∨ p) -> p := by myTactic
trace_state
Leonardo de Moura (Feb 09 2022 at 19:39):
Note that Or.elim
has implicit arguments
#check @Or.elim
So, mkApp (mkConst ``Or.elim) (mkFVar h)
is not constructing the term you are expecting.
We have some auxiliary functions for setting the value of implicit arguments (e.g., mkAppM
and mkAppOptM
). Here is an example:
elab "myTactic " : tactic => do
liftMetaTactic fun mvarId => do
let (h, mvarId) <- intro1P mvarId
let r ← cases mvarId h
withMVarContext mvarId do
let goals <- apply mvarId (← mkAppOptM ``Or.elim #[none, none, (← getMVarType mvarId), mkFVar h])
return goals
You can also use the cases
tactic at myTactic
. Example:
elab "myTactic " : tactic => do
liftMetaTactic fun mvarId => do
let (h, mvarId) <- intro1P mvarId
let r ← cases mvarId h
return r.toList.map (·.mvarId)
Leonardo de Moura (Feb 09 2022 at 19:49):
Not sure whether the following example is compatible with your plans, but evalTacticAt
may be useful
elab "myTactic " : tactic => do
let mvarId ← getMainGoal
let [mvarId] ← evalTacticAt (← `(tactic| intro h)) mvarId | unreachable!
let mvarIds ← evalTacticAt (← `(tactic| apply Or.elim h)) mvarId
replaceMainGoal mvarIds
Arthur Paulino (Feb 09 2022 at 19:55):
I tried something like that but I don't understand why h
is coming with a cross: h✝
:
case left
p : Prop
h✝ : p ∨ p
⊢ p → p
case right
p : Prop
h✝ : p ∨ p
⊢ p → p
It doesn't happen when doing intro h; apply Or.elim h
Alice Laroche (Feb 09 2022 at 20:02):
For the first one, i get
tactic apply failed, metavariable has already been assigned
The second one seem fine
The last example doesn't allow me to get the introducted fvars for futur uses, so it won't do the job.
Alice Laroche (Feb 09 2022 at 20:03):
Arthur Paulino said:
I tried something like that but I don't understand why
h
is coming with a cross:h✝
:case left p : Prop h✝ : p ∨ p ⊢ p → p case right p : Prop h✝ : p ∨ p ⊢ p → p
It doesn't happen when doing
intro h; apply Or.elim h
Those are the default name, you can change that behevior like that
elab "myTactic " : tactic => do
liftMetaTactic fun mvarId => do
let (h, mvarId) <- intro1P mvarId
let r ← cases mvarId h #[{ varNames := [`h]}, { varNames := [`h]}]
return r.toList.map (·.mvarId)
Arthur Paulino (Feb 09 2022 at 20:04):
Alice Laroche said:
For the first one, i get
tactic apply failed, metavariable has already been assigned
The second one seem fine
The last example doesn't allow me to get the introducted fvars for futur uses, so it won't do the job.
remove the line let r ← cases mvarId h
in the first one. It was probably a typo
Alice Laroche (Feb 09 2022 at 20:05):
Arthur Paulino said:
remove the line
let r ← cases mvarId h
in the first one. It was probably a typo
Ah yes, it make more sense...
Leonardo de Moura (Feb 09 2022 at 20:05):
I tried something like that but I don't understand why h is coming with a cross: h:cross::
It is because of hygiene.
Leonardo de Moura (Feb 09 2022 at 20:12):
If one wants they can workaround the hygienic macro system using tricks like
elab "myTactic " : tactic => do
let h := mkIdent `h
let mvarId ← getMainGoal
let [mvarId] ← evalTacticAt (← `(tactic| intro $h)) mvarId | unreachable!
let mvarIds ← evalTacticAt (← `(tactic| apply Or.elim $h)) mvarId
replaceMainGoal mvarIds
Last updated: Dec 20 2023 at 11:08 UTC