simp Attributes
Control simp's behavior with attributes. Mark lemmas as @[simp] to include them automatically in simplification.
The @[simp] Attribute
Mark lemmas with @[simp] to add them to simp's default lemma set:
lean
1@[simp]2theorem double_zero : double 0 = 0 := rfl34@[simp]5theorem double_succ (n : Nat) : double (n + 1) = double n + 2 := by6 simp [double]7 ring89-- Now simp uses these automatically10example : double 0 = 0 := by simp11example : double 1 = 2 := by simpKey Takeaway
@[simp] lemmas should rewrite left-to-right to simpler forms. They run automatically whenever you callsimp.Good simp Lemmas
lean
1-- Good: simplifies to a simpler form2@[simp] theorem add_zero (n : Nat) : n + 0 = n := rfl3@[simp] theorem mul_one (n : Nat) : n * 1 = n := rfl4@[simp] theorem not_not (b : Bool) : !!b = b := by cases b <;> rfl56-- Good: reduces constructors7@[simp] theorem fst_pair (a : α) (b : β) : (a, b).1 = a := rfl8@[simp] theorem head_cons (x : α) (xs : List α) : (x :: xs).head? = some x := rflBad simp Lemmas
lean
1-- Bad: loops forever!2-- @[simp] theorem comm (a b : Nat) : a + b = b + a -- DON'T DO THIS34-- Bad: makes terms bigger5-- @[simp] theorem expand (n : Nat) : n = n + 0 -- Wrong direction!67-- Bad: conditional without clear simplification8-- @[simp] theorem weird (n : Nat) (h : n > 0) : n = n -- Useless⚠
Never add commutative laws like
a + b = b + a as simp lemmas—they cause infinite loops! Simp would keep swapping forever.simp only
lean
1-- simp only uses ONLY the lemmas you specify2example (a b : Nat) : a + 0 + b = a + b := by3 simp only [Nat.add_zero]4 -- Only applies add_zero, nothing else56-- Useful for controlled simplification7example (xs : List Nat) : (xs ++ []).length = xs.length := by8 simp only [List.append_nil]Local simp Lemmas
lean
1-- Use hypotheses as simp lemmas2example (a b : Nat) (h : a = b) : a + 1 = b + 1 := by3 simp [h] -- Uses h : a = b as a rewrite rule45-- simp [*] uses ALL hypotheses6example (a b c : Nat) (h1 : a = b) (h2 : b = c) : a = c := by7 simp [*]simp_all
lean
1-- simp_all simplifies goal AND all hypotheses2example (a b : Nat) (h : a + 0 = b) : a = b := by3 simp_all4 -- Simplified h to: a = b, then used it56-- Powerful for cleaning up messy contexts7example (P Q : Prop) (h1 : P ∧ True) (h2 : Q ∧ P) : P := by8 simp_all -- Simplifies h1 to P, extracts PDeep Dive: simp's Lemma Database
When you call simp, it uses:
- All lemmas marked
@[simp]in scope - Built-in definitional equalities
- Any lemmas you pass explicitly with
simp [lemma]
lean
1-- See what simp lemmas exist for a type2#check @List.append_nil -- Has @[simp]3#check @Nat.add_zero -- Has @[simp]simp? for Discovery
lean
1-- simp? tells you which lemmas it used2example (xs : List Nat) : (xs ++ []).reverse = xs.reverse := by3 simp?4 -- Suggests: simp only [List.append_nil]56-- Useful for:7-- 1. Understanding what simp did8-- 2. Replacing simp with explicit simp only9-- 3. Learning which lemmas existExamples
Custom Type with simp Lemmas
lean
1structure Vec3 where2 x : Float3 y : Float4 z : Float56def Vec3.zero : Vec3 := ⟨0, 0, 0⟩78def Vec3.add (v w : Vec3) : Vec3 := 9 ⟨v.x + w.x, v.y + w.y, v.z + w.z⟩1011@[simp]12theorem Vec3.add_zero (v : Vec3) : v.add Vec3.zero = v := by13 simp [Vec3.add, Vec3.zero]14 -- Would need Float lemmas to completeControlled Simplification
lean
1example (xs ys : List Nat) (h : xs = []) : 2 (xs ++ ys).length = ys.length := by3 simp only [h, List.nil_append]