Zulip Chat Archive
Stream: lean4
Topic: MetaM and tactics
Guilherme Silva (May 01 2021 at 02:13):
How can I use MetaM as a tactic?
I have seen that most of the tactics are defined as MetaM in Lean 4 like simp
, rewrite
. But I copy and paste in my code and modified it a little bit and it is not working when I try to use it as a tactic.
Can someone give me a simple example of defining a small MetaM tactic and using it later?
Daniel Selsam (May 01 2021 at 03:10):
import Lean
open Lean Lean.Meta Lean.Elab.Tactic
def Meta.myTriv (mvarId : MVarId) : MetaM Unit := do
let mvarType ← getMVarType mvarId
if mvarType.isConstOf `True then
assignExprMVar mvarId (mkConst `True.intro [])
else
throwTacticEx `myTriv mvarId "goal does not have type `True`"
syntax (name := myTriv) "myTriv" : tactic
@[tactic myTriv] def evalMyTriv : Tactic := fun stx => do
let mvarId ← getMainGoal
Meta.myTriv mvarId
example : True := by myTriv
Mario Carneiro (May 01 2021 at 03:11):
import Lean
open Lean Elab Tactic Meta
def trivMetaM (mvarId : MVarId) : MetaM Unit := do
assignExprMVar mvarId (mkConst ``True.intro)
def trivTacticM : TacticM Unit :=
liftMetaMAtMain trivMetaM
syntax (name := triv) "triv" : tactic
@[tactic «triv»] def evalTriv : Tactic := fun stx =>
match stx with
| `(tactic| triv) => trivTacticM
| _ => throwUnsupportedSyntax
example : True := by triv
Mario Carneiro (May 01 2021 at 03:11):
dang
Mario Carneiro (May 01 2021 at 03:11):
same example too
Daniel Selsam (May 01 2021 at 03:12):
Ha. We need a better system. Next time I will type <SPACE> before I head to emacs, so it looks like I am typing in Zulip.
Mario Carneiro (May 01 2021 at 03:12):
it's good though, we need more examples of this stuff
Mario Carneiro (May 01 2021 at 03:12):
it's not clear to me whether macro
can be used here
Daniel Selsam (May 01 2021 at 03:15):
Mario Carneiro said:
it's not clear to me whether
macro
can be used here
Can you clarify your question? This works:
macro "myTriv" : tactic => `(exact True.intro)
example : True := by myTriv
Mario Carneiro (May 01 2021 at 03:15):
my version has a bug though, I guess assignExprMVar
doesn't check the types
Mario Carneiro (May 01 2021 at 03:16):
I mean for "proper" tactics, not macro tactics
Mario Carneiro (May 01 2021 at 03:17):
like what goes on the right of the arrow there? can some computation happen?
Daniel Selsam (May 01 2021 at 03:18):
Lean is expecting MacroM Syntax : Type
Mario Carneiro (May 01 2021 at 03:18):
I don't really know what that means though
Daniel Selsam (May 01 2021 at 03:19):
abbrev MacroM := ReaderT Macro.Context (EStateM Macro.Exception Macro.State)
Mario Carneiro (May 01 2021 at 03:20):
eh... yes
Daniel Selsam (May 01 2021 at 03:20):
It can perform some computation, but has no access to MetaM
and must return Syntax
Mario Carneiro (May 01 2021 at 03:20):
so it's a pure function?
Daniel Selsam (May 01 2021 at 03:21):
Yes.
Mario Carneiro (May 01 2021 at 03:21):
I guess that's a bit more restrained than the lean 3 parser
monad, which had access to the tactic state and a bunch of other stuff
Mario Carneiro (May 01 2021 at 03:22):
I mean, it's probably a good idea not to let the macros get too crazy but it might make some porting things tricky
Daniel Selsam (May 01 2021 at 03:22):
I think the idea is to separate concerns: have parsers parse and produce syntax, and then have elaborators map syntax to expressions.
Mario Carneiro (May 01 2021 at 03:23):
which is part of why I don't anticipate there being much use of macro tactics besides ad-hoc tactics that are done with `[ ... ]
today
Mario Carneiro (May 01 2021 at 03:24):
Even for something like triv
, if I actually cared to make a fast tactic with good error messages I wouldn't implement it as a macro tactic
Daniel Selsam (May 01 2021 at 03:26):
There are a bunch of "macro tactics" in Init
, e.g. https://github.com/leanprover/lean4/blob/master/src/Init/Notation.lean#L289-L305
Mario Carneiro (May 01 2021 at 03:28):
yes, and most of them will have to be replaced in mathlib... or at least that's my prediction
Mario Carneiro (May 01 2021 at 03:28):
it's not clear how to "scope creep" with those definitions
Daniel Selsam (May 01 2021 at 03:29):
(deleted)
Sebastian Ullrich (May 01 2021 at 07:42):
The point about "tactics are macros" is not that you have to write every tactic as a pure macro, but that it gives you a uniform macro/elaborator infrastructure shared with term elaboration, including the hygiene scheme. You can always "escalate" from a pure macro to an elaborator by throwing the syntax quotation in evalTactic
, then refine on top of that. For tactics that will probably happen more often than for terms, yes.
Guilherme Silva (May 01 2021 at 23:46):
I was looking at rewrite tactics and it returns MetaM RewriteResult
. So it looks like that transforming this MetaM into a tactic will not be a simple transformation. Where can I find some examples of a tactic that just changes a goal to a simpler goal?
Daniel Selsam (May 02 2021 at 00:31):
import Lean
open Lean Lean.Elab Lean.Elab.Tactic Lean.Meta
syntax (name := rewriteSimple) "rewriteSimple" term : tactic
@[tactic rewriteSimple] def evalRewriteSimple : Tactic := fun stx => do
Term.withSynthesize <| withMainContext do
let e ← elabTerm stx[1] none true
let r ← rewrite (← getMainGoal) (← getMainTarget) e
let mvarId' ← replaceTargetEq (← getMainGoal) r.eNew r.eqProof
replaceMainGoal (mvarId' :: r.mvarIds)
example (m n : Nat) (h : m = n) : m + m = n + n := by
rewriteSimple h
rfl
Guilherme Silva (May 02 2021 at 01:24):
Thanks for the example.
Do you know how to trace information? So I can understand what is going on.
Sebastian Ullrich (May 02 2021 at 07:19):
For unconditional tracing, you can use something like
logInfo m!"{e}: {r.eNew}"
See also https://leanprover.github.io/lean4/doc/debugging.html (additions welcome)
Guilherme Silva (May 02 2021 at 18:31):
Thank you for your suggestion. logInfo
is working inside Tactic and dbg_trace
is very useful when there is no logInfo
available.
Does MetaM have some kind of log? Because I have tried to use logInfo
inside it and it is not working :cry: . I received this error:
failed to synthesize instance
Lean.Elab.MonadLog (ReaderT.{0 0} Lean.Meta.Context (StateRefT' IO.RealWorld Lean.Meta.State Lean.Core.CoreM))
Guilherme Silva (May 02 2021 at 22:05):
I figure out that I can just rename MetaM to TacticM that it works. So it is possible to use all TacticM features :smiley:
Yakov Pechersky (May 02 2021 at 22:08):
There's also liftMetaAtMain
to lift MetaM
to TacticM
Guilherme Silva (May 03 2021 at 01:01):
@Yakov Pechersky , thanks for the suggestion.
I have found in the definition of MetaM
that they use StateRefT
, but my VSCode can't find the definition of it when I press F12
.
What is that? Why can't my VS Code find this definition?
Mario Carneiro (May 03 2021 at 01:16):
make sure you are up to date?
Leonardo de Moura (May 03 2021 at 01:23):
Guilherme Silva said:
Yakov Pechersky , thanks for the suggestion.
I have found in the definition of
MetaM
that they useStateRefT
, but my VSCode can't find the definition of it when I pressF12
.
What is that? Why can't my VS Code find this definition?
StateRefT
is currently a macro. This is a temporary workaround. Not sure whether it is still needed after all the recent improvements. Note that it is highlighted as a keyword.
We don't support goto definitions for macros yet.
Last updated: Dec 20 2023 at 11:08 UTC