Skip to content

Commit 2b51fb7

Browse files
committed
feat: port nth_rewrite (#823)
We just use features that are already in core. The implementation of `Occurrences` seems to be better than in Lean 3.
1 parent eb3149f commit 2b51fb7

File tree

4 files changed

+90
-1
lines changed

4 files changed

+90
-1
lines changed

Mathlib.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ import Mathlib.Tactic.NormCast.Tactic
261261
import Mathlib.Tactic.NormNum
262262
import Mathlib.Tactic.NormNum.Basic
263263
import Mathlib.Tactic.NormNum.Core
264+
import Mathlib.Tactic.NthRewrite
264265
import Mathlib.Tactic.PermuteGoals
265266
import Mathlib.Tactic.Positivity
266267
import Mathlib.Tactic.Positivity.Basic

Mathlib/Mathport/Syntax.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import Mathlib.Tactic.ModCases
4343
import Mathlib.Tactic.Nontriviality
4444
import Mathlib.Tactic.NormCast
4545
import Mathlib.Tactic.NormNum
46+
import Mathlib.Tactic.NthRewrite
4647
import Mathlib.Tactic.PermuteGoals
4748
import Mathlib.Tactic.Positivity
4849
import Mathlib.Tactic.PushNeg
@@ -358,7 +359,6 @@ syntax mono.side := &"left" <|> &"right" <|> &"both"
358359
tactic
359360
/- B -/ syntax (name := equivRwType) "equiv_rw_type" (config)? term : tactic
360361

361-
/- N -/ syntax (name := nthRw) "nth_rw " num rwRuleSeq (ppSpace location)? : tactic
362362
/- E -/ syntax (name := nthRwLHS) "nth_rw_lhs " num rwRuleSeq (ppSpace location)? : tactic
363363
/- E -/ syntax (name := nthRwRHS) "nth_rw_rhs " num rwRuleSeq (ppSpace location)? : tactic
364364

Mathlib/Tactic/NthRewrite.lean

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/-
2+
Copyright (c) 2022 Moritz Doll. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Moritz Doll
5+
-/
6+
7+
import Lean.Elab.Tactic.Rewrite
8+
import Lean.Elab.BuiltinTerm
9+
10+
/-!
11+
# `nth_rewrite` tactic
12+
13+
The tactic `nth_rewrite` and `nth_rw` are variants of `rewrite` and `rw` that only performs the
14+
`n`th possible rewrite.
15+
16+
-/
17+
namespace Mathlib.Tactic
18+
19+
open Lean Elab Tactic Meta Parser.Tactic
20+
21+
/-- Variant of `rewriteTarget` that allows to use `Occurrences`.
22+
23+
This def should be in Core. -/
24+
def rewriteTarget' (stx : Syntax) (symm : Bool) (occs : Occurrences := Occurrences.all)
25+
(config : Rewrite.Config := { : Rewrite.Config }) : TacticM Unit := do
26+
Term.withSynthesize <| withMainContext do
27+
let e ← elabTerm stx none true
28+
let r ← (← getMainGoal).rewrite (← getMainTarget) e symm occs config
29+
let mvarId' ← (← getMainGoal).replaceTargetEq r.eNew r.eqProof
30+
replaceMainGoal (mvarId' :: r.mvarIds)
31+
32+
/-- Variant of `rewriteLocalDecl` that allows to use `Occurrences`.
33+
34+
This def should be in Core. -/
35+
def rewriteLocalDecl' (stx : Syntax) (symm : Bool) (fvarId : FVarId)
36+
(occs : Occurrences := Occurrences.all) (config : Rewrite.Config := { : Rewrite.Config }) :
37+
TacticM Unit := do
38+
Term.withSynthesize <| withMainContext do
39+
let e ← elabTerm stx none true
40+
let localDecl ← fvarId.getDecl
41+
let rwResult ← (← getMainGoal).rewrite localDecl.type e symm occs config
42+
let replaceResult ← (← getMainGoal).replaceLocalDecl fvarId rwResult.eNew rwResult.eqProof
43+
replaceMainGoal (replaceResult.mvarId :: rwResult.mvarIds)
44+
45+
/-- `nth_rewrite` is a variant of `rewrite` that only changes the nth occurrence of the expression
46+
to be rewritten.
47+
48+
Note: The occurrences are counted beginning with `1` and not `0`, this is different than in
49+
mathlib3. The translation will be handled by mathport. -/
50+
syntax (name := nthRewriteSeq) "nth_rewrite " (config)? num rwRuleSeq (ppSpace location)? : tactic
51+
52+
@[inherit_doc nthRewriteSeq, tactic nthRewriteSeq] def evalNthRewriteSeq : Tactic := fun stx => do
53+
match stx with
54+
| `(tactic| nth_rewrite $[$_cfg]? $n $_rules $[$_loc]?) =>
55+
-- [TODO] `stx` should not be used directly, but the corresponding functions do not yet exist
56+
-- in Lean 4 core
57+
let cfg ← elabRewriteConfig stx[1]
58+
let loc := expandOptLocation stx[4]
59+
let occ := Occurrences.pos [n.getNat]
60+
withRWRulesSeq stx[0] stx[3] fun symm term => do
61+
withLocation loc
62+
(rewriteLocalDecl' term symm · occ cfg)
63+
(rewriteTarget' term symm occ cfg)
64+
(throwTacticEx `nth_rewrite · "did not find instance of the pattern in the current goal")
65+
| _ => throwUnsupportedSyntax
66+
67+
/--
68+
`nth_rw` is like `nth_rewrite`, but also tries to close the goal by trying `rfl` afterwards.
69+
-/
70+
macro (name := nthRwSeq) "nth_rw" c:(config)? n:num s:rwRuleSeq l:(location)? : tactic =>
71+
-- Note: This is a direct copy of `nth_rw` from core.
72+
match s with
73+
| `(rwRuleSeq| [$rs,*]%$rbrak) =>
74+
-- We show the `rfl` state on `]`
75+
`(tactic| (nth_rewrite $(c)? $n [$rs,*] $(l)?; with_annotate_state $rbrak
76+
(try (with_reducible rfl))))
77+
| _ => Macro.throwUnsupported

test/NthRewrite.lean

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import Mathlib.Tactic.NthRewrite
2+
import Mathlib.Algebra.Group.Defs
3+
4+
example [AddZeroClass G] {a : G} (h : a = a): a = (a + 0) := by
5+
nth_rewrite 2 [←add_zero a] at h
6+
exact h
7+
8+
example [AddZeroClass G] {a : G} : a + a = a + (a + 0) := by
9+
nth_rw 2 [←add_zero a]
10+
11+
-- Porting note: Port all tests from mathlib3 once `data.nat.basic` and `data.vector` are ported

0 commit comments

Comments
 (0)