ポリモーフィズム

一つのコード/インターフェースが複数の型に対して動作する性質(「多くの形」)。OOP では普通部分型多相(動的ディスパッチ)を指すが、プログラミング言語論ではより広い分類がある。Cardelli & Wegner (1985) の整理が定番。

分類

ポリモーフィズム
├─ universal(無限個の型に一様に効く)
│   ├─ parametric  … パラメトリック多相 / ジェネリクス
│   └─ subtype     … 部分型多相 / 包含多相
└─ ad-hoc(有限個の型ごとに別実装)
    ├─ overloading … オーバーロード(型クラス/trait で規律化)
    └─ coercion    … 型強制(暗黙変換)
種類別名例解決時点
parametricジェネリクス・総称型List<T>, id : a -> a型に依らず単一コード
subtype部分型・包含OOP の継承・interface(GADTとは別軸)主に実行時(動的ディスパッチ)
overloadingアドホック・型クラス+ の多重定義, Haskell type class, Rust traitコンパイル時
coercion型強制int → double 暗黙変換コンパイル時

parametric — 「型に何もできない」がゆえに安全

型をパラメータ化し、中身の型に依存しない同一コードを書く。

id   :: a -> a          -- a に対して何もできない= id を返すしかない
fst  :: (a, b) -> a
length :: [a] -> Int    -- 要素の型を見られないので、数えることしかできない

型変数に対して操作できないため、取りうる実装が型シグネチャで強く縛られる(parametricity、“theorems for free”)。これが parametric の安全性の源。

ad-hoc — 型ごとに分岐、型クラスで規律化

オーバーロードは「同名・型ごとに別実装」。素朴には無秩序だが、型クラス(Haskell)/ trait(Rust) が型システム上で整理した形。

class Show a where show :: a -> String   -- 型ごとに show の実装を与える
instance Show Int  where show = ...
instance Show Bool where show = ...

これは Tagless Final の土台でもある(操作を型クラスで宣言し、解釈をインスタンスで与える)。

実装メカニズム(同じ多相でもコストが違う)

方式中身コスト代表
動的ディスパッチvtable / 仮想メソッドで実行時に解決間接呼び出し・インライン化困難OOP の継承, Rust dyn Trait
単相化(monomorphization)型ごとに特化コードを生成ゼロコスト、ただしコード膨張・コンパイル増C++ template, Rust ジェネリクス
辞書渡し(dictionary passing)型クラスのメソッド表を暗黙引数で渡す間接化ありHaskell type class
型消去(type erasure)実行時に型情報を捨て一様表現実行時に型が見えないJava generics

Rust の trait は 単相化(速い)と dyn(動的)を選べる点で、ad-hoc と境界付き parametric を融合している。

なぜ重要か

コード再利用と抽象化の中核。同じロジックを型をまたいで一度だけ書く。parametric は「振る舞いが型で決まらない」ことで安全、ad-hoc は「型ごとに振る舞いを変える」柔軟さを与える — 目的が逆で、両方要る。

その他の多相

関連

Graph