Zulip Chat Archive
Stream: metaprogramming / tactics
Topic: How do I match on syntax.
metakuntyyy (Jan 18 2026 at 17:36):
So I want to implement a rewrite and clear tactic. However I can't match on the syntax rwRuleSeq.
import Mathlib
open Lean
open Meta
open Lean.Elab.Tactic
open Lean.Meta.Tactic
open Lean.Parser.Tactic
syntax (name := rwc) "rwc " rwRuleSeq : tactic
@[tactic rwc]
def rewrite_and_clear : Tactic := fun stx => withMainContext do
match stx with
| `(rwRuleSeq) =>
logInfo m! "ayayay"
| _ =>
logInfo m! "{stx}"
theorem dada (a b : ℕ ) (h : a = b) : a+b = b := by
rwc [h]
sorry
I'd like to enter the first match arm so that I can call the rewrite tactic and then I'd like to call some clear tactics.
Aaron Liu (Jan 18 2026 at 17:41):
what are you trying to do
Aaron Liu (Jan 18 2026 at 17:41):
rwRuleSeq is not a syntax, it is a syntax category
metakuntyyy (Jan 18 2026 at 17:43):
I'm trying to match on [$rs,*] inside rewrite_and_clear, but I don't know how to enter the first arm.
metakuntyyy (Jan 18 2026 at 17:43):
Got the code from here https://github.com/leanprover/lean4/blob/2fcce7258eeb6e324366bc25f9058293b04b7547/src/Init/Tactics.lean#L603
metakuntyyy (Jan 18 2026 at 17:43):
I'd like to have access to the main context, so the code in the rewrite tactic doesn't work..
Aaron Liu (Jan 18 2026 at 17:44):
what do you want to do with this syntax
Aaron Liu (Jan 18 2026 at 17:45):
there is docs#Lean.Elab.Tactic.withRWRulesSeq
metakuntyyy (Jan 18 2026 at 17:45):
Well the rwRuleSeq should hopefully contain the hypotheses that I can clear. Other then that I'd pass the call to the rw tactic.
Aaron Liu (Jan 18 2026 at 17:46):
you can access the parts of the syntax I guess
import Mathlib
open Lean Parser Elab Tactic
syntax (name := rwc) "rwc " rwRuleSeq : tactic
@[tactic rwc]
def rewrite_and_clear : Tactic := fun stx => do
logInfo stx[0] -- `rwc`
logInfo stx[1] -- `[h]`
logInfo stx[1][0] -- `[`
logInfo stx[1][1] -- `h`
logInfo stx[1][1][0] -- `h`
logInfo stx[1][2] -- `]`
set_option pp.rawOnError true
theorem dada (a b : ℕ ) (h : a = b) : a+b = b := by
rwc [h]
sorry
metakuntyyy (Jan 18 2026 at 17:48):
Cool, can you show me how to do it with match? so that the first arm gives me "rwc" and the second arm gives me [$rs,*]?
Aaron Liu (Jan 18 2026 at 17:50):
you can get the rewrite rules like this
import Mathlib
open Lean Parser Elab Tactic
syntax (name := rwc) "rwc " rwRuleSeq : tactic
macro_rules
| `(tactic| rwc [$[$rs:rwRule],*]) => do
Macro.throwUnsupported
Aaron Liu (Jan 18 2026 at 17:52):
or like this
import Mathlib
open Lean Parser Elab Tactic
syntax (name := rwc) "rwc " rwRuleSeq : tactic
example (stx : Syntax.Tactic) : MetaM Unit := do
match stx with
| `(tactic| rwc [$[$rs:rwRule],*]) =>
return
| _ => throwUnsupportedSyntax
metakuntyyy (Jan 18 2026 at 17:56):
How do I hook it up?
import Mathlib
open Lean Parser Elab Tactic
syntax (name := rwc) "rwc " rwRuleSeq : tactic
example (stx : Syntax.Tactic) : TacticM Unit := do
match stx with
| `(tactic| rwc [$[$rs:rwRule],*]) =>
logInfo m! "HAA"
return
| _ =>
logInfo m! "BOO"
return
theorem dada (a b : ℕ ) (h : a = b) : a+b = b := by
rwc [h]
sorry
I want to enter the first arm and it should print HAA, not BOO
Aaron Liu (Jan 18 2026 at 17:58):
like this I guess?
import Mathlib
open Lean Parser Elab Tactic
syntax (name := rwc) "rwc " rwRuleSeq : tactic
def runRwc (stx : Syntax.Tactic) : TacticM Unit := do
match stx with
| `(tactic| rwc [$[$rs:rwRule],*]) =>
logInfo m! "HAA"
return
| _ =>
logInfo m! "BOO"
return
@[tactic rwc]
def elabRwc : Tactic := fun stx => runRwc ⟨stx⟩
theorem dada (a b : ℕ ) (h : a = b) : a+b = b := by
rwc [h]
sorry
metakuntyyy (Jan 18 2026 at 17:59):
@Aaron Liu It works. :tada:
metakuntyyy (Jan 18 2026 at 18:10):
Ok, cool. Inside a TacticM Unit, how can I execute a tactic, like exfalso for example. `(tactic| exfalso) does not work.
Aaron Liu (Jan 18 2026 at 18:11):
docs#Lean.Elab.Tactic.evalTactic
metakuntyyy (Jan 18 2026 at 18:15):
Nvm it works.
import Mathlib
open Lean Parser Elab Tactic
syntax (name := rwc) "rwc " rwRuleSeq : tactic
def runRwc (stx : Syntax.Tactic) : TacticM Unit := withMainContext do
match stx with
| `(tactic| rwc $s:rwRuleSeq) =>
match s with
| `(rwRuleSeq| [$rs,*]) =>
let seq := rs.getElems
let y := seq[0]!
let d ← `(tactic| exfalso)
let e ← evalTactic d
return
| _ => return
| _ =>
logInfo m! "BOO"
return
@[tactic rwc]
def elabRwc : Tactic := fun stx => runRwc ⟨stx⟩
theorem dada (a b : ℕ ) (h : a = b) (h2: b=2): a+b = b := by
rwc [h, h2]
sorry
metakuntyyy (Jan 18 2026 at 18:22):
Apparently I had to use double bind. :joy:
metakuntyyy (Jan 18 2026 at 19:17):
Ok, so I have succeeded in rewriting and clearing. Now, how can I improve it?
import Mathlib
open Lean Parser Elab Tactic
syntax (name := rwc) "rwc" rwRuleSeq : tactic
set_option pp.rawOnError true
def runRwc (stx : Syntax.Tactic) : TacticM Unit := withMainContext do
match stx with
| `(tactic| rwc $s:rwRuleSeq) =>
match s with
| `(rwRuleSeq| [$rs,*]) =>
let seq := rs.getElems
logInfo m! "{s}"
let l := seq.toList
let d ← `(tactic|rw [$rs,*])
evalTactic d
for x in l do
let yy := x.raw[1]
let traw : TSyntax `term := TSyntax.mk yy
let tc ← `(tactic| clear $traw)
let d ← evalTactic tc
return
| _ => return
| _ =>
logInfo m! "BOO"
return
@[tactic rwc]
def elabRwc : Tactic := fun stx => runRwc ⟨stx⟩
theorem dada (a b : ℕ ) (h : a = b) (h2: b=2): a+b = b := by
rwc[h,h2]
sorry
Last updated: Feb 28 2026 at 14:05 UTC