列挙型と代数的データ型
今日はなごやかJava第1回 - connpassに行って来ました。
そこで@bleisさんによるJavaとC#(とF#)の比較の話の中で列挙型(と代数的データ型)について話題に上がりました。
SML好きな自分が最近C++を書いてて同じように2つの違いについて思ったことがあったので、ここに書いておきます。
列挙型
- (おそらく)有限数状態を表すために作られた
- int等でもプログラマが管理すれば同様の機能は実現できる
- 状態の意味を名前付けしたり、状態数の制限を付加できる
- C/C++やJavaなどで使える*1
- ラベルのみを持つ
- 使用例
// C++ // 定義 enum Janken { Gu, Choki, Pa }; // 使用 int walkLength(Janken hand) { switch(hand) { Gu: return 3 // グリコ Choki: return 6 // チョコレート Pa: return 6 // パイナップル } }
代数的データ型
- 数学の直和が理論の元になっている
- 集合A,Bに対して2つの直和A+Bは A+B = { a_label(x) | x∈A } ∪ { b_label(x) | x∈B }
- つまり、どちらの集合から来たかラベルが付いた和集合
- HaskellやOCamlやSMLやScalaで使える
- 型推論が効く
- 強力なパターンマッチが使える
- 列挙型と違い、ラベルだけでなくデータも持てる
- そもそも列挙ではなく、複数の型を直和した別な型をつくる概念
- Cでいう共用体(union)にラベルが付いている、ほうが正しく表していると思う
- 暗黙の型変換は存在しない
- 使用例
(* SML *) (* 定義 *) datatype janken = Gu | Choki | Pa | LocalRule of string * int (* 使用 *) fun walkLength hand = (* 型推論結果: fn: janken -> int *) case hand of Gu => 3 | Choki => 6 | Pa => 6 | LocalRule (name, n) => n (* "グリコノオマケ"、など *)