rfl — Reflexivity
rfl proves that something equals itself. It's the most fundamental tactic and often the first you'll learn.
The Basic Idea
Every value equals itself. That's the reflexivity of equality:
lean
1-- Anything equals itself2example : 5 = 5 := rfl3example : "hello" = "hello" := rfl4example : [1, 2, 3] = [1, 2, 3] := rflBut rfl is more powerful than it looks. It works whenever Lean can compute both sides to the same value:
lean
1-- These compute to the same value2example : 2 + 2 = 4 := rfl -- 2 + 2 computes to 43example : 10 - 3 = 7 := rfl -- 10 - 3 computes to 74example : 2 * 3 + 1 = 7 := rfl -- Computed: 7 = 756-- String operations too7example : "hel" ++ "lo" = "hello" := rfl89-- List operations10example : [1, 2] ++ [3] = [1, 2, 3] := rflKey Takeaway
rfl works when both sides of an equalitycompute (or "reduce") to the same term. Lean evaluates as much as it can before comparing.When rfl Works
lean
1-- Definitional equality: both sides compute to the same thing2example : (fun x => x + 1) 5 = 6 := rfl -- Function application34example : [1, 2, 3].length = 3 := rfl -- Method call56example : (if true then 1 else 2) = 1 := rfl -- Conditional78def double (n : Nat) : Nat := n * 29example : double 5 = 10 := rfl -- User-defined functionWhen rfl Fails
rfl can't prove things that require reasoning beyond computation:
lean
1-- These require actual reasoning, not just computation23-- example : a + b = b + a := rfl 4-- Fails! Lean doesn't know what a and b are56-- example : n + 0 = n := rfl7-- Fails for arbitrary n (even though true by definition for specific n)89-- example : n * 1 = n := rfl10-- Fails! Requires induction to prove for all n⚠
rfl only works for definitional equality—when things compute to the same value. For propositional equality (things that are equal but don't directly compute), you need other tactics.rfl as a Tactic vs Term
rfl can be used both as a proof term and as a tactic:
lean
1-- As a term (no 'by')2example : 2 + 2 = 4 := rfl34-- As a tactic (with 'by')5example : 2 + 2 = 4 := by rfl67-- They're equivalent, but the tactic version gives better error messagesRelated: Eq.refl
rfl is notation for Eq.refl, which explicitly takes the value:
lean
1-- These are the same2example : 5 = 5 := rfl3example : 5 = 5 := Eq.refl 545-- Eq.refl has type: ∀ (a : α), a = a6#check @Eq.refl -- {α : Sort u} → (a : α) → a = aDeep Dive: Definitional vs Propositional Equality
Lean has two notions of equality:
- Definitional equality: Two terms compute to the same value. Checked automatically.
rflproves this. - Propositional equality: Two terms are provably equal via some chain of reasoning. Requires explicit proof.
For example, 2 + 2 and 4 are definitionally equal. But n + 0 and nare only propositionally equal (proven by the lemma Nat.add_zero).
Common Uses
Proving computed results
lean
1-- After computation, things equal themselves2example : (3 + 4) * 2 = 14 := rfl3example : "abc".length = 3 := rfl4example : [1, 2, 3].reverse = [3, 2, 1] := rflClosing goals after rewriting
lean
1example (a b : Nat) (h : a = b) : b = a := by2 rw [h] -- Goal becomes: b = b3 rfl -- Trivially trueShowing function application
lean
1def f (x : Nat) : Nat := x + 123example : f 5 = 6 := rfl -- f 5 computes to 5 + 1 = 6The native_decide Alternative
For decidable propositions that take too long to compute with rfl, use native_decide:
lean
1-- This might be slow with rfl for large numbers2example : 123456 + 789012 = 912468 := by native_decide34-- native_decide uses compiled code, which is much faster