第4章のオブジェクト指向は「状態を持つオブジェクト」を中心に据える世界でした。本章では、それとは対極にある もう一つの大きな系譜——状態と副作用を避け、関数の合成で計算を組み立てる 関数型プログラミングを辿ります。そしてもう一つ、言語の安全性を静かに支えてきた縁の下の力持ち、 型システムの進化を見ていきます。この2つは、現代の言語デザインの最前線で再び主役になっています。

理論の源流 — λ計算(1930年代)

関数型の物語は、コンピュータが存在する前から始まっています。1930年代、数学者アロンゾ・チャーチが λ計算(lambda calculus)という計算の数学的モデルを考案しました。これは「すべての計算を、 関数の定義と適用だけで表現する」という驚くほどミニマルな体系です。

興味深いことに、チャーチのλ計算と、アラン・チューリングのチューリング機械は、同じ計算能力を持つことが証明されました (チャーチ=チューリングのテーゼ)。つまり「関数の適用」だけで、コンピュータにできるあらゆる計算が表現できる—— これが関数型プログラミングの理論的支柱です。そしてこの抽象的な数学を、最初に動く言語にしたのが、 第2章で登場したLISP(1958)でした。

関数型の核心 — 純粋さと参照透過性

関数型プログラミングの中心思想は「純粋関数(pure function)」です。純粋関数とは、 同じ入力には必ず同じ出力を返し、外部の状態を変更する「副作用」を持たない関数のこと。 この性質を参照透過性(referential transparency)と呼びます。

-- 純粋関数: 同じ入力には必ず同じ出力。副作用なし
double :: Int -> Int
double x = x * 2

-- 関数の合成で計算を組み立てる
-- map で各要素に関数を適用(命令的なループを書かない)
result :: [Int]
result = map double [1, 2, 3]   -- => [2, 4, 6]

なぜこれが重要なのでしょうか。純粋関数は外部に影響を与えず、外部からも影響されないため、 並列化が安全(順序を気にせず同時実行できる)、結果のキャッシュが可能(同じ入力なら再計算不要)、 そして形式的検証やテストが容易になります。OOPが「可変状態の管理」で悩んだまさにその部分を、 関数型は「そもそも状態を持たない」ことで回避するのです。

観点 OOP/命令型 関数型
中心概念 状態を持つオブジェクト、逐次的な命令 純粋関数とその合成、式の評価
状態の扱い 可変(mutable)を前提に管理 不変(immutable)を基本とする
ループ for/while で明示的に反復 map/filter/reduce や再帰で表現
得意なこと 現実のモデル化、UIや状態機械 並列処理、データ変換、検証可能性

ML と型推論 — 「正しい型なら間違えない」

関数型のもう一つの大きな貢献が型システムです。1970年代前半、エディンバラ大学のロビン・ミルナーは、 定理証明システムLCFのメタ言語として ML を開発しました。MLが持ち込んだ革命が型推論(type inference)です。

それまで、静的な型を持つ言語(Pascalなど)では、変数や関数の型を人間がいちいち書く必要がありました。 MLは「型を書かなくても、コンパイラが文脈から型を自動的に推論する」仕組みを実現します。 ミルナーは1978年の論文「A Theory of Type Polymorphism in Programming」で型推論アルゴリズムWを提示し、 有名な標語「well-typed programs cannot go wrong(型が正しいプログラムは実行時に型エラーを起こさない)」を 数学的に証明しました。この仕組みは発明者2人の名からHindley-Milner型システムと呼ばれます。

-- 型注釈を書かなくても、コンパイラが型を推論する
square x = x * x       -- コンパイラは square :: Num a => a -> a と推論

-- 多相型: どんな型のリストにも使える length
-- length :: [a] -> Int  (aは任意の型)
len = length [1,2,3]   -- => 3

Haskell(1990)— 純粋関数型の集大成

関数型の理想を最も純粋な形で結晶させたのが Haskell(1990年に最初の仕様)です。 Haskellは委員会によって設計された、研究と実用を橋渡しする標準的な純粋関数型言語で、3つの特徴を備えます。

  • 純粋性の徹底: 副作用を型システムで隔離する。I/Oのような副作用は IO 型で明示的に扱う
  • 遅延評価(lazy evaluation): 値は本当に必要になるまで計算しない。無限リストすら自然に扱える
  • 強力な型システム: 型クラス、モナドといった抽象化で、純粋さと実用性を両立する
-- 遅延評価の威力: 無限リストから先頭5個だけ取り出す
naturals :: [Integer]
naturals = [1..]           -- 1から始まる無限リスト(だが即座には計算しない)

firstFive :: [Integer]
firstFive = take 5 naturals  -- => [1,2,3,4,5]  必要な分だけ計算される

Haskellは主流の座を獲得したわけではありませんが、その影響は絶大です。Haskellで磨かれた型クラス、 パターンマッチ、不変データ、モナドといったアイデアは、Scala・Rust・Swift・Kotlin、さらにはJavaやC#、JavaScriptへと流れ込み、 「関数型の良いところ」を主流言語が次々と取り込む流れを生みました。

静的 vs 動的 — 型をめぐる長い対立

型システムには、根深い対立軸があります。静的型付け(コンパイル時に型を決める)と 動的型付け(実行時に型が決まる)のどちらを選ぶか、です。

静的型付け 動的型付け
代表 C, Java, Haskell, Rust, TypeScript Python, Ruby, JavaScript, LISP
型チェック コンパイル時(実行前) 実行時
利点 バグの早期発見、補完・最適化が効く 柔軟で記述が軽快、試行錯誤が速い
欠点 記述がやや増える、硬い 実行時まで型エラーが分からない

長らくこれは「どちらが優れているか」の宗教論争のように扱われてきました。しかし2020年代の答えは、 意外にも「両方とる」でした。

収斂 — 漸進的型付けという和解

近年の大きな潮流が漸進的型付け(gradual typing)です。これは、動的型付け言語に 「型注釈を後から、必要な部分だけ付け足せる」仕組みを導入するもの。動的型の柔軟さで素早く書き始め、 コードが成熟したら型を加えて安全性を高める——両者の良いとこ取りです。

最も成功した例が TypeScript(2012, Microsoft)です。動的型のJavaScriptに静的型を後付けし、 大規模開発に耐えうる安全性をもたらしました。同様に、Pythonもtype hintsmypy による 型チェックがほぼ標準になり、Rubyにも型注釈の流れが広がっています。

// TypeScript: JavaScriptに型注釈を後付けする
function greet(name: string): string {
  return `Hello, ${name}!`;
}

greet("World");   // OK
// greet(42);      // コンパイル時にエラー: number は string に代入できない
graph TD
  LC[λ計算\n1930s Church\n理論的基盤]
  LISP[LISP\n1958 最初の実装]
  ML[ML\n1973 型推論]
  HM[Hindley-Milner\n1978 型理論]
  HS[Haskell\n1990 純粋関数型の集大成]
  MULTI[主流言語へ流入\nScala/Rust/Swift/TS\nマルチパラダイム化]
  LC --> LISP
  LC --> ML
  ML --> HM
  HM --> HS
  ML --> HS
  HS --> MULTI
  LISP --> MULTI
  style LC fill:#3b82f6,stroke:#1d4ed8,color:#fff
  style HM fill:#8b5cf6,stroke:#6d28d9,color:#fff
  style HS fill:#f97316,stroke:#ea580c,color:#fff
  style MULTI fill:#14b8a6,stroke:#0d9488,color:#fff
関数型と型システムの系譜。λ計算からLISP・ML・Haskellを経て、その成果が主流言語に流入しマルチパラダイム化が進む

λ計算

アロンゾ・チャーチ。関数の定義と適用だけで計算を表す数学的モデル。関数型の理論的基盤

LISP

マッカーシー。λ計算を最初に実装した言語。再帰・第一級関数・GC

ML

ロビン・ミルナー。LCF定理証明系のメタ言語。型推論を持つ最初の言語

Hindley-Milner型理論

ミルナーの論文。型推論アルゴリズムWと「型が正しければ実行時型エラーなし」の証明

Haskell

純粋関数型・遅延評価・型クラスの集大成。研究と実用を橋渡し

TypeScript / 漸進的型付け

動的言語に静的型を後付け。静的vs動的の対立は「両取り」へ収斂

理解度チェック

問題 0 / 50%
Q1

関数型プログラミングの理論的基盤となった、1930年代にアロンゾ・チャーチが考案した計算モデルは何ですか?

キーボード: 1〜4 で選択、Enter で回答