conv — Targeted Rewriting
conv lets you navigate into subexpressions and rewrite precisely where you want, solving the "I can't rewrite the right occurrence" problem.
The Problem conv Solves
Standard rw rewrites all matching occurrences, or just the first one. When you need to rewrite a specific occurrence deep inside an expression,conv lets you navigate to exactly that spot.
lean
1-- Sometimes rw rewrites the wrong occurrence2example (a b : Nat) : (a + b) * (a + b) = (b + a) * (a + b) := by3 -- rw [Nat.add_comm] -- Would rewrite both occurrences!4 conv => 5 lhs -- focus on left-hand side6 arg 1 -- first argument of *7 rw [Nat.add_comm]8 -- Now goal is: (b + a) * (a + b) = (b + a) * (a + b)9 rflKey Takeaway
conv enters a "conversation mode" where you navigate to a subexpression and apply tactics to just that part.Navigation Commands
Inside conv, you use navigation commands to "zoom in" on subexpressions. The main commands are lhs/rhsfor equation sides, arg n for function arguments, andext for going under binders.
lean
1-- lhs / rhs: go to left or right side of equation2example (a b : Nat) : a + b = b + a := by3 conv => 4 lhs5 rw [Nat.add_comm]67-- arg n: go to nth argument (1-indexed)8example (a b c : Nat) : (a + b) + c = (b + a) + c := by9 conv =>10 lhs11 arg 1 -- go to (a + b)12 rw [Nat.add_comm]1314-- ext: introduce binders (for under lambdas/foralls)15example : (fun x : Nat => x + 0) = (fun x => x) := by16 conv =>17 lhs18 ext x -- introduce x19 rw [Nat.add_zero]Common conv Patterns
lean
1-- Rewrite inside a function argument2example (xs : List Nat) : xs.map (· + 0) = xs.map id := by3 conv =>4 lhs5 arg 1 -- the function argument6 ext x7 rw [Nat.add_zero]8 simp [id]910-- Rewrite one side of iff11example (P Q : Prop) (h : P ↔ Q) : (P ∧ True) ↔ (Q ∧ True) := by12 conv =>13 lhs14 arg 115 rw [h]1617-- Nested navigation18example (a b c d : Nat) : ((a + b) + c) + d = ((b + a) + c) + d := by19 conv =>20 lhs21 arg 1 -- (a + b) + c22 arg 1 -- a + b23 rw [Nat.add_comm]Tactics Inside conv
lean
1-- rfl: close with reflexivity2example (a : Nat) : a + 0 = a := by3 conv => lhs; rw [Nat.add_zero]45-- ring/omega inside conv6example (a b : Nat) : (a + b) * 2 = 2 * (b + a) := by7 conv => 8 rhs9 rw [Nat.add_comm]10 ring1112-- simp at specific location13example (xs : List Nat) : xs.reverse.reverse = xs := by14 conv => lhs; simpDeep Dive: conv Mode Navigation
Think of conv as zooming into your expression:
lean
1-- Expression: f (g (h x)) (k y)2-- 3-- conv =>4-- arg 1 -- f (g (h x)) (k y) → g (h x)5-- arg 1 -- g (h x) → h x6-- arg 1 -- h x → x78-- Other navigation:9-- pattern e -- go to subexpression matching pattern e10-- enter [n] -- same as arg n but for any position11-- all -- apply to all subexpressionspattern Matching
lean
1-- Navigate by pattern matching2example (a b c : Nat) : a + (b + c) = a + (c + b) := by3 conv =>4 rhs5 pattern b + c -- find and focus on b + c6 rw [Nat.add_comm]78-- Multiple patterns9example (a b : Nat) : (a + 0) + (b + 0) = a + b := by10 conv =>11 lhs12 pattern _ + 013 rw [Nat.add_zero]14 -- Still have one more to do15 conv =>16 lhs17 pattern _ + 018 rw [Nat.add_zero]ℹ
Use
pattern when the expression is complex and counting args would be error-prone.Exercise: Rewrite One Occurrence
Use conv to rewrite just one occurrence of a + b.
lean
1example (a b : Nat) : (a + b) + (a + b) = (b + a) + (a + b) := by2 conv =>3 lhs4 arg 15 rw [Nat.add_comm]6 rflconv with simp
lean
1-- simp only at specific positions2example (xs : List Nat) (f : Nat → Nat) : 3 (xs.map f).length = xs.length := by4 conv => lhs; simp [List.length_map]56-- Avoid unwanted simplification7example (a b : Nat) : (a + b) * 1 = a + b := by8 conv => 9 lhs10 arg 2 -- the 111 -- don't simp the whole thing, just verify * 112 simp [Nat.mul_one]Changing Under Binders
lean
1-- ext to go under lambda2example : (fun x : Nat => x * 2) = (fun x => 2 * x) := by3 conv =>4 lhs5 ext x6 rw [Nat.mul_comm]78-- Under forall9example : (∀ x : Nat, x + 0 = x) ↔ (∀ x : Nat, x = x) := by10 constructor11 · intro h x12 have := h x13 simp at this14 exact this15 · intro _ x16 simpExamples
Specific Occurrence Rewrite
lean
1example (a b c : Nat) : a + b + c = c + b + a := by2 conv =>3 lhs4 rw [Nat.add_assoc]5 arg 26 rw [Nat.add_comm]7 conv =>8 lhs9 rw [← Nat.add_assoc]10 arg 111 rw [Nat.add_comm]12 ringSimplify Function Body
lean
1example (f : Nat → Nat) (h : ∀ n, f n = n + 1) : 2 (fun x => f x + 1) = (fun x => x + 2) := by3 conv =>4 lhs5 ext x6 rw [h]7 ring_nfRewrite in Hypothesis
lean
1example (a b : Nat) (h : a + b = 10) : b + a = 10 := by2 conv at h =>3 lhs4 rw [Nat.add_comm]5 exact h