rfl

rfl は、定義に展開すれば等しそうなもの同士が等しいことを示すタクティクです。

/-- 自前で定義した自然数 -/
inductive MyNat where
  | zero
  | succ (n : MyNat)

namespace MyNat
  /- ## 足し算の定義 -/

  /-- MyNat の足し算 -/
  def add : MyNat → MyNat → MyNat
    | a, .zero => a
    | a, .succ b => .succ (add a b)

  /-- MyNat.add を `+` で書けるようにする -/
  instance : Add MyNat where
    add := MyNat.add

end MyNat

/-- 1 に相当する項 -/
def MyNat.one : MyNat := .succ zero

/-- 2 に相当する項 -/
def MyNat.two : MyNat := .succ one

/-- 1 + 1 = 2 に相当する命題 -/
example : MyNat.one + MyNat.one = MyNat.two := by
  rfl

#reduce コマンドとの関係

ここで「定義に展開すれば等しそう」というのは、おおむね #reduce コマンドに与えた結果の式が等しいという意味です。

section
  -- フィールド記法を無効にする
  set_option pp.fieldNotation false

  /- info: MyNat.succ (MyNat.succ MyNat.zero) -/
  #reduce MyNat.one + MyNat.one

  /- info: MyNat.succ (MyNat.succ MyNat.zero) -/
  #reduce MyNat.two
end

ただし、rfl で示せる等式と、#reduce コマンドでの両辺の簡約結果が等しい等式とは完全には一致しません。以下のように、両辺の #reduce 結果は異なるものの rfl で示せる等式も存在します。

section
  variable {α : Type} {β : α → Type} (f : (x : α) → β x)

  /- info: f -/
  #reduce f

  /- info: fun x => f x -/
  #reduce (fun x => f x)

  example : f = (fun x => f x) := by
    rfl

end

カスタマイズ

rfl は、実は等式だけでなく一般の反射的(reflexive)な関係 R に対して関係式 R a b を示すために使用することができます。ここで二項関係 R : α → α → Prop が反射的であるとは、任意の ∀ a, R a a が成り立つことをいいます。

関係 R が反射的であることを rfl に利用させるには、R の反射性を示した定理に [refl] 属性を付与します。

universe u

-- `MyEq` という二項関係を定義する
inductive MyEq {α : Type u} : α → α → Prop where
  | refl (a : α) : MyEq a a

example (n : Nat) : MyEq n n := by
  -- `rfl` で示すことはできない。
  fail_if_success rfl

  apply MyEq.refl

-- `MyEq` が反射的であることを登録する
attribute [refl] MyEq.refl

-- `rfl` で示せるようになった!
example (n : Nat) : MyEq n n := by rfl