多相バリアントについて
多相バリアントについては,
あたりを読むとよいでしょう.(この記事では解説しません).
多相レコードについて
多相レコードについては,
を読むとよいでしょう.
多相レコードによる多相バリアントの表現について
多相レコードによる多相バリアントの表現については,
などに,詳しく書かれております.
多相レコードで多相バリアントができるなら,多相バリアントで多相レコードもできるはず!
と,考えまして, OCaml の多相バリアントで多相レコードが実装できないか試しました.
多相バリアントで多相レコード
結論としてはこうなります.
let id x = x
let pair x y = function `Fst f -> f x | `Snd f -> f y
let fst p = p (`Fst id)
let snd p = p (`Snd id)
let triple x y z = function `Fst f -> f x | `Snd f -> f y | `Third f -> f z
let third p = p (`Third id)
(* fst は pair/triple のどちらに対しても使える *)
let i = fst (pair 1 'a')
let j = fst (triple 2 'b' 3.14)
注意(追記)
OCaml には (Relaxed) Value Restriction があるので,ちゃんと使うには η expansion
する必要があります.
let id x = x
let pair x y = function `Fst f -> f x | `Snd f -> f y
let fst p = p (`Fst id)
let snd p = p (`Snd id)
let triple x y z = function `Fst f -> f x | `Snd f -> f y | `Third f -> f z
let third p = p (`Third id)
let p = fun x -> pair 1 'a' x
let i = fst p
let j = snd p
蛇足なこと
最初,ADTをオブジェクト指向言語におけるメッセージだと捉えて,次のような構造を考えました.
let pair x y = function `Fst -> x | `Snd -> y
let fst p = p `Fst
let snd p = p `Snd
let triple x y z = function `Fst -> x | `Snd -> y | `Third -> z
let third p = p `Third
(* fst は pair/triple のどちらに対しても使える *)
let i = fst (pair 1 2)
let j = fst (triple 2 3 4)
しかし,これだと, pair x y
の x と y が同じ型でないといけないことになってしまいます.
let pair x y = function `Fst -> x | `Snd -> y
let fst p = p `Fst
let snd p = p `Snd
let triple x y z = function `Fst -> x | `Snd -> y | `Third -> z
let third p = p `Third
(* こういうペアはつくれない *)
let p = pair 1 'b'
そこで関数をひとつ噛ませるという工夫をしました.
ペアの定義は
let pair x y = function `Fst f -> f x | `Snd f -> f y
let fst p = p (`Fst id)
let snd p = p (`Snd id)
こうすることで,ペアのそれぞれが異なる型でもうまく動くようになりましたとさ.