TL

依存型と証明としてのプログラム

範囲外参照や長さ不一致を、テストではなくコンパイル時に消せる。値に依存する型で不変条件を保証し、Curry-Howard対応により証明とプログラムを同一視する仕組みが分かる。

応用型理論依存型形式手法関数型証明支援系最終更新: 2026-06-21
TL;DR要点だけ先に
  • 1.依存型は値に依存する型。長さ n のベクタ型 Vect n a のように、型の中に値を埋め込めるため、配列の範囲外参照や長さ不一致をコンパイル時に排除できる。
  • 2.Curry-Howard対応を量化子まで深めると、全称型 Π は「すべての〜について」、存在型 Σ は「ある〜が存在する」に対応し、型が命題、項がその証明になる。
  • 3.Idris/Agda/Leanでは証明とプログラムが同じ言語の項。型検査の通過が証明の完成であり、型が成り立たない仕様なら、そもそも値を構成できない。

依存型とは「値に依存する型」

通常の型システムでは、型と値は別の世界にいます。Int という型は、それが 37 かを知りません。依存型(dependent types)はこの壁を壊し、型が値に依存することを許します。たとえば「長さ n のベクタ」を Vect n a と書けます。ここで n は型ではなく(自然数)であり、それが型の一部に組み込まれています。Vect 3 IntVect 4 Int は異なる型であり、両者を取り違えるとコンパイル時に弾かれます。

この一歩がもたらす効果は大きい。配列アクセスのような、これまで実行時例外でしか守れなかった不変条件を、型のレベルで初めから表現できるようになります。

範囲外参照を型で消す

依存型の威力がもっとも分かりやすいのが、安全な添字アクセスです。要素数を n とすると、有効な添字は 0 以上 n 未満です。この「n 未満」という制約を、型に持つ添字 Fin n0 から n - 1 までしか値を持たない有限型)で表現します。

-- Idris2 風の擬似コード
index : Fin n -> Vect n a -> a

index は「長さ n のベクタと、n 未満であることが保証された添字」しか受け取りません。Vect 3 a に対して添字 5 を渡そうとすると、5Fin 3 に当てはめられず、コンパイルが通りません。範囲チェックを実行時に書く必要も、テストで網羅する必要もない。型検査器が、すべての呼び出しについて範囲内であることを一度に証明してくれます。

型と値の境界が消える

依存型を持つ言語では「型を計算する関数」も普通に書けます。たとえば replicate : (n : Nat) -> a -> Vect n a の戻り値の型 Vect n a は、第1引数の値 n に依存して決まります。型は固定された注釈ではなく、値から計算される第一級の存在になります。型レベルと値レベルが同じ言語で書ける——これがラムダ計算と型理論で触れたラムダキューブの「型が項に依存する」軸の正体です。

Curry-Howard対応の深化:量化子まで

ラムダ計算と型理論で見たCurry-Howard対応は「型=命題、プログラム=証明」でした。依存型は、この対応を量化子(全称・存在)まで押し広げます。鍵は2つの型構成子です。

型構成子論理での意味プログラムでの意味
Π型(依存関数型)全称量化 ∀x. P(x)引数 x の値ごとに戻り値の型が変わる関数
Σ型(依存ペア型)存在量化 ∃x. P(x)ある値 x と、それが P を満たす証拠の組

普通の関数型 A -> B は、戻り値の型 B が引数に依存しない特殊な Π 型です。Π 型では戻り値の型が引数のに依存できる。だから「すべての自然数 n について、n 個の要素を持つベクタを返す」という主張=型を書け、その型を持つ項を構成することが、その主張の構成的な証明になります。Σ 型は「条件を満たす値が存在する」ことを、実際の値と証拠のペアとして示します。等しさそのものを表す等式型a = b)も型として存在し、refl(反射律)がその証明項になります。

証明とプログラムの同一視

依存型の言語では、証明とプログラムは同じ言語の項です。両者を分ける境界はありません。型検査が通ることが、対応する命題の証明が完成したことに等しい。たとえば「リスト連結の長さは、各リストの長さの和に等しい」という定理は、次のような型を持つ関数として書けます。

-- Agda 風の擬似コード: ++ の長さは length の和に等しい
length-++ : (xs : Vect m a) -> (ys : Vect n a)
          -> length (xs ++ ys) = m + n

この型を持つ項を、両リストの構造に関する帰納法で構成できれば、定理は証明されたことになります。逆に命題が偽なら、その型を持つ項はどうやっても作れず、コンパイルが通りません。「正しいことしか型付かない」ため、型が成り立つこと自体が安全性の保証になります。これは代数的データ型のパターンマッチ網羅性検査を、任意の不変条件にまで一般化したものと見ることもできます。

全域性と健全性

証明として成立させるには、関数が全域(total)でなければなりません。停止しない関数や、一部の入力を扱わない関数を許すと、嘘の証明が作れてしまいます。たとえば loop : A のように自分自身を無限に呼ぶ項に任意の型を付けられると、任意の命題が「証明」できてしまう。そこで Agda や Idris は停止性検査と網羅性検査を行い、証明として使う部分は全域であることを要求します。健全性(嘘を証明できないこと)は、この全域性に支えられています。

Idris / Agda / Lean:三者の立ち位置

依存型を実用する代表が Idris、Agda、Lean です。理論的な核(依存型と Curry-Howard 対応)は共有しつつ、狙いが異なります。

言語主な狙い特徴
Idris依存型による実用プログラミング汎用言語として設計。型駆動開発、量的型理論で線形性も扱う
Agda型理論の研究と証明対話的な穴埋め(ホール)で証明を組み立てる。パターンマッチが中心
Lean数学の形式化と定理証明強力なタクティクと巨大な数学ライブラリ mathlib。証明の自動化が手厚い

Idris は「依存型をジェネリックな開発で使う」方向で、型が定まると関数の実装候補が絞られる型駆動開発を前面に出します。Agda は証明の対話的構築に重きを置き、未完成箇所を「ホール」として残しながら型に導かれて埋めていきます。Lean は数学の形式化に強く、タクティク(証明を組み立てる命令の連なり)で大規模な証明を構成し、近年の形式数学プロジェクトの基盤になっています。

証明項とタクティクは別物ではない

Lean のタクティクは魔法ではなく、最終的には Curry-Howard 対応の通りに証明項(型を持つ普通の項)を生成しています。introapplyinduction といったタクティクは、それぞれ関数抽象・関数適用・帰納法による項構成に対応します。タクティクは項を手で書く手間を自動化する「項の組み立てスクリプト」であり、生成結果は型検査器で再確認できます。

何にコストを払うのか

依存型は強力ですが、ただ取りではありません。型が値に依存するため、型の等しさを判定するには値を計算(簡約)して比較する必要があり、型検査が一般に決定不能になり得ます。実用言語は全域性や簡約の範囲を制限してこれを御します。また、不変条件を型に載せるほど、その不変条件を維持する証明をプログラマが書くコストが増えます。等式の書き換えや帰納法の手当てが必要になり、記述量は増えます。

すべてを依存型で守る必要はない

実務では、本当に壊れて困る中核の不変条件(長さ、範囲、状態機械の遷移など)だけを依存型で固め、残りは通常の型とプロパティベーステストで担保する、という段階的な使い分けが現実的です。証明のコストと、防げるバグの重大さを天秤にかけるのは、設計判断そのものです。

まとめ

依存型は、型と値の境界を取り払い、値に依存する型として不変条件をコンパイル時に表現する仕組みです。Curry-Howard 対応を量化子(ΠΣ)まで深めると、型は命題、項は証明となり、Idris・Agda・Lean では証明とプログラムが同じ言語の項として一体化します。型検査が通ること自体が、その仕様が成り立つことの証明である——この見方は、型システムを「制約のチェック」から「仕様の証明」へと読み替える、もっとも先鋭的な到達点です。コストはあるものの、絶対に壊したくない一点を型で封じる道具として、依存型は確かな選択肢になります。

プログラミング Article

依存型と証明としてのプログラムを実務で読む

TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。

解決すること

型理論

比較で見る軸

難易度: advanced / カテゴリ: プログラミング / タグ数: 5

導入後に効く点

Curry-Howard対応を量化子まで深めると、全称型 Π は「すべての〜について」、存在型 Σ は「ある〜が存在する」に対応し、型が命題、項がその証明になる。

先に潰すリスク

用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。

数字・仕様の読み方
難易度
advanced
カテゴリ
プログラミング
タグ数
5

判断チェックリスト

  • 自社の用途が「型理論 / 依存型」に近いか確認する。
  • 強みである「依存型は値に依存する型。長さ n のベクタ型 Vect n a のように、型の中に値を埋め込めるため、配列の範囲外参照や長さ不一致をコンパイル時に排除できる。」が本当に評価軸になるか確認する。
  • 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
  • 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
  • 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
  • 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。

次に確認する観点

型理論依存型形式手法関数型証明支援系型理論依存型形式手法