have

have は、証明の途中でわかることをローカルコンテキストに追加するコマンドです。

have h : P := ...P という命題の証明を構成し、その証明に h という名前を付けることができます。

import Mathlib.Tactic.Ring -- `ring` のため

variable (P Q R : Prop)

example (hPQ: P → Q) (hQR: Q → R) : P → R := by
  -- 示したいことが `P → R` なので、`P` だと仮定する
  intro hP

  -- 仮定 `hPQ : P → Q` と `hP : P` から `Q` が導かれる
  have hQ : Q := by exact hPQ hP

  -- 仮定 `hQR : Q → R` と `hQ : Q` から `R` が導かれる
  exact hQR hQ

have で示した補題には必ず名前がつきます。名前を省略して have : P := ... とすると、自動的に this という名前になります。無名の補題が欲しい場合、代わりに show を検討してみてください。

また have で同じ名前を2回宣言すると、古い方はアクセス不能になってしまいます。ローカルコンテキストの補題の置き換えを行いたいときは、代わりに replace を使用してください。

無名コンストラクタ

P の証明 hp : PQ の証明 hq : Q があるとき、P ∧ Q の証明は And.intro hp hq で構成できます。ここで And.intro は構造体 And 型のコンストラクタです。

これを、コンストラクタ名を明示せずにシンプルに ⟨hp, hq⟩ と書くことができます。これは無名コンストラクタと呼ばれるもので、And に限らず任意の構造体に使用することができます。

variable (hp : P) (hq : Q)

def hpq : P ∧ Q := ⟨hp, hq⟩
def hpq' : P ∧ Q := And.intro hp hq

無名コンストラクタを利用することで、記述を簡略化できます。

論理積 ∧

次のように、P ∧ Q という命題から PQ を取り出すことができます。

example (hPQ : P ∧ Q) : P := by
  -- `P ∧ Q` という仮定を分解する
  -- `hQ : Q` は不要なのでアンダースコアに置き換える
  have ⟨ hP, _ ⟩ := hPQ

  assumption

存在 ∃

次のように、∃ x: X, P x という命題から、条件を満たす x を取り出すことができます。x : Xhx : P x がローカルコンテキストに追加されます。

-- `x`が偶数のとき`3 * x`も偶数
example (x : ℕ) (hx : ∃ y, x = 2 * y) : ∃ z, 3 * x = 2 * z := by
  -- `hx` で存在が主張されている `y` と、
  -- `x = 2 * y` という命題を得る
  have ⟨y, hy⟩ := hx
  exists 3 * y
  rw [hy]
  ring