直観主義論理
「証拠を構成しないと真とは言えない」という立場の論理。
プログラマ向けの一言
「存在する」と言うなら実際に作って見せろ、という論理。 古典論理では「存在しないと矛盾する、だから存在する」が通るが、直観主義では「実際に構成して見せて初めて存在する」。
古典論理との違い
// 古典論理: 排中律(P または ¬P は常に真)を認める
// 「素数は無限にある。なぜなら、有限だと仮定すると矛盾するから」
// → 矛盾を示せば OK。実際に素数を1つずつ構成する必要はない
// 直観主義論理: 排中律を仮定しない
// 「素数は無限にある」を示すには、任意の n に対して
// n 番目の素数を実際に構成するアルゴリズムを示す必要がある
// プログラマ的に言うと:
function classicalProof(): boolean {
// 「P が偽だと矛盾する」→「P は真」
// 背理法で存在を示すが、実際の値は得られない
return true; // ... でも具体的な値は?
}
function constructiveProof(): { value: number; proof: string } {
// 「P を満たす値を実際に構成する」
return { value: 42, proof: "ここに具体的な構成がある" };
// → 証明 = プログラム(値を計算して返す)
}
排中律と二重否定除去
// 古典論理で認められ、直観主義で認められないもの:
// 1. 排中律: P ∨ ¬P(P か not P のどちらか)
// 型で言うと: 任意の型 A に対して A | (A => never) が得られる
// → 直観主義では「A の値があるか、A が矛盾を導くか」の
// どちらかを必ず決められるとは限らない
// 2. 二重否定除去: ¬¬P → P
// 型で言うと: ((A => never) => never) => A
// → 「A がないと矛盾する」ことから A を取り出す
function doubleNeg<A>(proof: (notA: (a: A) => never) => never): A {
// ... これを実装する方法がない!
// 矛盾を示せても、A の具体的な値は得られない
throw "impossible in constructive logic";
}
// 逆(P → ¬¬P)は直観主義でも成り立つ:
function introDoubleNeg<A>(a: A): (notA: (a: A) => never) => never {
return (notA) => notA(a); // A の値があるなら、¬A に渡せば矛盾する
}
なぜプログラミングに関係するか
// カリー=ハワード対応で:
// 命題 = 型、証明 = プログラム
//
// 直観主義の証明 = 実行可能なプログラム
// 古典論理の証明 = 実行可能とは限らない(存在は示すが構成しない)
//
// だから型システムは本質的に直観主義論理に対応する
// → Coq, Agda, Lean などの定理証明系はすべて直観主義論理ベース
// → 「証明する」=「プログラムを書く」が成り立つのは直観主義だから
押さえどころ(カード化候補)
- 直観主義論理とは → 「存在する」と言うなら実際に証拠を構成して見せろ、という立場の論理。背理法で存在を示すだけでは不十分
- 古典論理との違い → 古典は排中律 (P∨¬P) を認め背理法で存在を示せる。直観主義は具体的な構成 (アルゴリズム) を要求する
- 認めない2規則 → 排中律 P∨¬P と二重否定除去 ¬¬P→P は不成立 (矛盾を示せても A の値は得られない)。逆向き P→¬¬P は直観主義でも成立
- カリー=ハワード対応 → 命題=型、証明=プログラム。直観主義の証明は実行可能なプログラムに対応し、古典論理の証明は実行可能とは限らない
- 型システムとの関係 → 型システムは本質的に直観主義論理に対応。Coq/Agda/Lean などの定理証明系はすべて直観主義論理ベース
関連
- カリー=ハワード同型対応 — 直観主義論理 ⟺ 型付きλ計算
- 推論規則 — 論理の推論を形式化するルール
- 定理証明 — 直観主義論理に基づく証明系
- 時相論理 — 別の非古典論理