ushumpei’s blog

生活で気になったことを随時調べて書いていきます。

Lean4 学習

Lean が気になっているので Theorem Proving in Lean 4 の Propositions and Proofs にある演習問題を解いた。プログラムによる定理証明に触れるのは初なので、時々型を定理だと認識できなくなって迷走してしまうなど苦労した。

Lean4 が気になっている理由としては

  • 定理証明支援系で堅牢なソフトウェアかけるんじゃないかなという期待
  • Lean4 が関数型言語 + 定理証明支援系 という部分

定理証明支援系の使用例を調べてみたが、今回の学習からどう繋がっていくかイメージがまだついていない

問題を載せることに関しては Apache License 2.0 のため大丈夫な認識

以下

variable (p q r : Prop)

-- commutativity of ∧ and ∨
example : p ∧ q ↔ q ∧ p := Iff.intro
  (fun hpq => ⟨hpq.right, hpq.left⟩)
  (fun hqp => ⟨hqp.right, hqp.left⟩)
example : p ∨ q ↔ q ∨ p := Iff.intro
  (fun hpq => hpq.elim
    (fun hp => Or.inr hp)
    (fun hq => Or.inl hq))
  (fun hqp => hqp.elim
    (fun hq => Or.inr hq)
    (fun hp => Or.inl hp))

-- associativity of ∧ and ∨
example : (p ∧ q) ∧ r ↔ p ∧ (q ∧ r) := Iff.intro
  (fun h => ⟨h.left.left, ⟨h.left.right, h.right⟩⟩)
  (fun h => ⟨⟨h.left, h.right.left⟩, h.right.right⟩)
example : (p ∨ q) ∨ r ↔ p ∨ (q ∨ r) := Iff.intro
  (fun h => h.elim
    (fun hpq => hpq.elim
      (fun hp => Or.inl hp)
      (fun hq => Or.inr (Or.inl hq)))
    (fun hr => Or.inr (Or.inr hr)))
  (fun h => h.elim
    (fun hp => Or.inl (Or.inl hp))
    (fun hqr => hqr.elim
      (fun hq => Or.inl (Or.inr hq))
      (fun hr => Or.inr hr)))

-- distributivity
example : p ∧ (q ∨ r) ↔ (p ∧ q) ∨ (p ∧ r) := Iff.intro
  (fun h => have hp := h.left
    h.right.elim
    (fun hq => Or.inl (And.intro hp hq))
    (fun hr => Or.inr (And.intro hp hr)))
  (fun h => h.elim
    (fun hpq => And.intro hpq.left (Or.inl hpq.right))
    (fun hpr => And.intro hpr.left (Or.inr hpr.right)))
example : p ∨ (q ∧ r) ↔ (p ∨ q) ∧ (p ∨ r) := Iff.intro
  (fun h => h.elim
    (fun hp => And.intro (Or.inl hp) (Or.inl hp))
    (fun hqr => And.intro (Or.inr hqr.left) (Or.inr hqr.right)))
  (fun h =>
    have hpq := h.left
    have hpr := h.right
    hpq.elim
      (fun hp => Or.inl hp)
      (fun hq => hpr.elim
        (fun hp => Or.inl hp)
        (fun hr => Or.inr (And.intro hq hr))))

-- other properties
example : (p → (q → r)) ↔ (p ∧ q → r) := Iff.intro
  (fun hpqr =>
    fun hpq =>
    hpqr hpq.left hpq.right)
  (fun h =>
    fun hp =>
    fun hq =>
    h (And.intro hp hq))
example : ((p ∨ q) → r) ↔ (p → r) ∧ (q → r) := Iff.intro
  (fun h =>
    And.intro
    (fun hp => h (Or.inl hp))
    (fun hq => h (Or.inr hq)))
  (fun h =>
    fun hpq => hpq.elim
    (h.left)
    (h.right))
example : ¬(p ∨ q) ↔ ¬p ∧ ¬q := Iff.intro
  (fun hnpq => And.intro
    (fun hp => hnpq (Or.inl hp))
    (fun hq => hnpq (Or.inr hq)))
  (fun h =>
    have hnp := h.left
    have hnq := h.right
    fun hpq => hpq.elim hnp hnq)
example : ¬p ∨ ¬q → ¬(p ∧ q) :=
  fun h =>
  fun hpq => h.elim
    (fun hnp => hnp hpq.left)
    (fun hnq => hnq hpq.right)
example : ¬(p ∧ ¬p) :=
  fun h => h.right h.left
example : p ∧ ¬q → ¬(p → q) :=
  fun h₁ => fun h₂ => h₁.right (h₂ h₁.left)
example : ¬p → (p → q) :=
  fun hnp => fun hp => absurd hp hnp
example : (¬p ∨ q) → (p → q) := 
  fun h => fun hp => h.elim
    (fun hnp => absurd hp hnp)
    (fun hq => hq)
example : p ∨ False ↔ p := Iff.intro
  (fun h => h.elim (fun hp => hp) (fun hf => hf.elim))
  (fun hp => Or.inl hp)

example : p ∧ False ↔ False := Iff.intro
  (fun h => h.right.elim)
  (fun h => h.elim)
example : (p → q) → (¬q → ¬p) :=
  fun hpq => fun hnq => fun hp => hnq (hpq hp)

open Classical

variable (p q r : Prop)

example : (p → q ∨ r) → ((p → q) ∨ (p → r)) :=
  fun h => (em p).elim
    (fun hp => (h hp).elim
      (fun hq => Or.inl fun _ => hq)
      (fun hr => Or.inr fun _ => hr))
    (fun hnp => Or.inl (fun hp => absurd hp hnp))
example : ¬(p ∧ q) → ¬p ∨ ¬q :=
  fun h => (em p).elim
    (fun hp => (em q).elim
      (fun hq => (h (And.intro hp hq)).elim)
      (fun hnq => Or.inr hnq))
    (fun hnp => Or.inl hnp)
example : ¬(p → q) → p ∧ ¬q :=
  fun hn => 
    (em p).elim
    (fun hp =>
      have hnq : ¬q := fun hq =>
        have h : p → q := fun _ => hq
        absurd h hn
      And.intro hp hnq)
    (fun hnp =>
      have h : p → q := fun hp => absurd hp hnp
      absurd h hn)
example : (p → q) → (¬p ∨ q) :=
  fun hpq => (em p).elim
    (fun hp => Or.inr (hpq hp))
    (fun hnp => Or.inl hnp)
example : (¬q → ¬p) → (p → q) :=
  fun h => fun hp => (em q).elim
    (id)
    (fun hnq => absurd hp (h hnq))
example : p ∨ ¬p := em p
example : (((p → q) → p) → p) := (em p).elim
  (fun hp => fun _ => hp)
  (fun hnp => fun h =>
    have hpq : p → q := fun hp => absurd hp hnp 
    absurd (h hpq) hnp)

感想

  • 排中律を使った証明が難しい
  • have ... absurd で補題を示していく感じにしているがもっと良い書き方ありそう
  • And.intro の方がカッコを使った書き方より見やすそう
  • フォーマッター欲しい、ちゃんと読んでないけど話はある?(https://github.com/leanprover/lean4/issues/369)
  • 関数型言語の側面をうまく使えていないかもしれない
  • 依存型がわかってない
  • Type と Prop の差異が曖昧、Prop : Type?
  • そういえば定理証明支援系って言葉あまり意味を理解していないで使っている
    • 定理証明支援系を使って書かれたコードは証明?証明を使ったソフトウェア開発とかいうべき?