cases

cases は場合分けを行うことができるタクティクです。

たとえば、ローカルコンテキストに h : P ∨ Q があるときに cases h とすると、仮定に P を付け加えたゴールと、仮定に Q を付け加えたゴールをそれぞれ生成します。

よく似たタクティクに rcases があります。

example (P Q R : Prop) : P ∨ Q → (P → R) → (Q → R) → R := by
  -- `h: P ∨ Q`
  intro h hPR hQR

  -- `inl` と `inr` の2つのゴールを生成する
  cases h with

  -- `P` が成り立つ場合
  | inl hP =>
    exact hPR hP

  -- `Q` が成り立つ場合
  | inr hQ =>
    exact hQR hQ

=> を省略することもできます。

example (P Q R : Prop) : P ∨ Q → (P → R) → (Q → R) → R := by
  intro h hPR hQR

  cases h with | inl hP | inr hQ

  · exact hPR hP
  · exact hQR hQ

case タクティク

cases .. with 構文を使わずに、case タクティクを使って次のように書くこともできます。

example (P Q R : Prop) : P ∨ Q → (P → R) → (Q → R) → R := by
  intro h hPR hQR

  cases h

  case inl hP =>
    apply hPR
    assumption

  case inr hQ =>
    apply hQR
    assumption

舞台裏

帰納型の分解

cases は、実際には論理和に限らず帰納型をコンストラクタに分解することができるタクティクです。

-- 帰納型として定義した例示のための型
inductive Sample where
  | foo (x y : Nat)
  | bar (z : String)

example (s : Sample) : True := by
  -- cases で場合分けを実行できる
  cases s

  case foo x y =>
    trivial

  case bar z =>
    trivial

論理和を分解することができるのも、Or が次のように帰納型として定義されているからです。

inductive Or (a b : Prop) : Prop where
  | inl (h : a)
  | inr (h : b)

帰納的述語の分解

特に、帰納的述語も cases タクティクで分解することができます。 仮定がどのコンストラクタから来たものなのかに応じて場合分けをすることができます。

たとえば、以下のように偶数であることを表す帰納的述語を定義したとします。 このとき Even (n + 2) という仮定があれば Even n を結論出来ますが、これは cases タクティクで行うことができます。

/-- 偶数であることを表す帰納的述語 -/
inductive Even : Nat → Prop where
  | zero : Even 0
  | cons {n : Nat} (ih : Even n) : Even (n + 2)

example (n : Nat) (h : Even (n + 2)) : Even n := by
  -- h に対して場合分けを行う。
  -- `Even (n + 2)` という仮定はどのコンストラクタから来たか?で場合分けできる。
  -- `cases` タクティクはある程度賢いので、
  -- `zero` のケースはありえないと判断してスキップできる。
  cases h with
  | cons ih =>
    exact ih