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