Zulip Chat Archive
Stream: lean4
Topic: Tactic by manipulating Expr
Tomas Skrivan (Sep 23 2021 at 16:54):
If I have a function Expr -> MetaM (Expr × Expr)
that turns an expression to an another expression and also provide a proof that they are equal. How do I turn this into a tactic that rewrites the goal?
Also, what if I have only Expr -> MetaM Expr
but can also generate tactic proof of that the output is equal to the input. How can I make a tactic to rewrite the goal?
I had a rough idea how to do it in lean3 but in lean4 I'm stomped.
Jakob von Raumer (Sep 23 2021 at 17:24):
First use that function in a function MVarId -> MetaM MVarId
which returns a new MVar
with the new goal, assigns the input MVar
with the result of substituting with the equality and assigning the substituted MVar
with the new MVar
.
Then you need to define a Tactic
which calls that function and sets the main goal to its output.
Tomas Skrivan (Sep 23 2021 at 18:58):
Thanks! It pointed me to the right direction.
Actually, the function more or less exists already Lean.Meta.replaceTargetEq
:)
I still need to figure out what is the best way to create the equality proof(its Expr
representation) if I know the tactic proof for it.
Chris B (Sep 23 2021 at 19:07):
There are some examples in the current version of mathlib4's normNum, particularly here. https://github.com/leanprover-community/mathlib4/blob/7ac569847b94980d3d668ae6079131f5cd2fe559/Mathlib/Tactic/NormNum.lean#L104
Tomas Skrivan (Sep 23 2021 at 20:09):
I think, I'm on the right track, but running into problems with universes(something I do not really understand)
I'm trying to write a simple tactic that replaces the current goal X
with two new goals X = id X
and id X
. The first goal X = id X
should be solvable by simp
but I'm getting an error incorrect number of universe levels id
import Lean
import Lean.Meta.Basic
import Lean.Elab.Tactic.Basic
open Lean
open Lean.Meta
open Lean.Elab.Tactic
syntax (name := mytactic) "mytactic" : tactic
def mytacticCore (mvarId : MVarId) : MetaM (List MVarId) :=
withMVarContext mvarId do
let tag ← getMVarTag mvarId
let target ← getMVarType mvarId
let u ← getLevel target
let targetNew := (mkApp (mkConst `id) target)
let mvarNew ← mkFreshExprSyntheticOpaqueMVar targetNew tag
let eq ← mkEq target targetNew
let eqMvar ← mkFreshExprSyntheticOpaqueMVar eq tag
let val := mkAppN (Lean.mkConst `Eq.mpr [u]) #[target, targetNew, eqMvar, mvarNew]
assignExprMVar mvarId val
return [eqMvar.mvarId!, mvarNew.mvarId!]
@[tactic mytactic] def tacticMytactic : Tactic
| _ => do
let mainGoal ← getMainGoal
let todos ← mytacticCore mainGoal
setGoals todos
pure ()
theorem test (X : Type) (x : X) : id x = x :=
by
mytactic
simp
Chris B (Sep 23 2021 at 20:36):
id needs a universe. Without looking too careully at it I would assume you can just use u
here:
let targetNew := (mkApp (mkConst `id [u]) target)
Chris B (Sep 23 2021 at 20:39):
If you print a declaration and it has a little .{u}
or something else tacked onto the end, that means it takes one or more (one in this case) universe parameters in this context.
#print id
-- def id.{u} : {α : Sort u} → α → α := ..
Tomas Skrivan (Sep 23 2021 at 21:00):
Thanks! Makes sense. I just recalled from "Lean Together 2021: Metaprogramming in Lean 4" that there is mkAppM
that deals will all of this for me. So switching two lines to:
let targetNew ← mkAppM `id #[target]
let val ← mkAppM `Eq.mpr #[eqMvar, mvarNew]
Makes it work and I do not have to deal with universes and implicit arguments.
Chris B (Sep 23 2021 at 21:41):
Nice, that does seem handy.
Last updated: Dec 20 2023 at 11:08 UTC