private row素晴らしすぎる
詳細はまた書くけど、「最低限こーゆーもの」を抽象化して輸入できる。素晴らしすぎる。
[追記]
例えば、二次元座標上の点を表現する何かを定義する。
class type ['a] point = object method x : 'a method y : 'a end
このpoint型はgetterしか持ってないことに注意。値を変更することもできないし構築することもできない、実質座標を参照したいだけの型だ。
そして、このような参照だけ可能な型を使った点のリストを表現したいとする。まず思い付くのは#を使った次のような方法。
module RV = struct type 'a p = int #point as 'a type 'a t = 'a p list let make () = [] let add (s : 'a p) t = s :: t let show (t : 'a t) = List.iter (fun s -> Printf.printf "x=%d,y=%d\n" s#x s#y) t end
#pointは型変数を含むので、明示的に'aを付けてやる必要がある。これはこれでうまくいく。例えば、次のような点クラスを作ってRVに使える。
class ['a] z_point ~x ~y ~z = object val x : 'a = x with accessor val y : 'a = y with accessor val z : 'a = z with accessor end let _ = RV.show @@ RV.add (new z_point ~x:1 ~y:2 ~z:3) @@ RV.add (new z_point ~x:4 ~y:5 ~z:6) @@ RV.make ()
これでx=1,y=2とx=4,y=5が表示される。
ただ、type 'a pの定義には明示的な型変数が出てしまい、この型を利用する側としては有り難くない。そこでprivate row typeの登場。
module PVは次のように書ける。
module PV (X : sig type p = private int #point end) = struct type t = X.p list let make () = [] let add s t : t = s :: t let show (t : t) = List.iter (fun s -> Printf.printf "x=%d,y=%d\n" s#x s#y) t end
型変数の部分が型宣言内でprivate化されていて、表の型には型変数が必要ない。すばらしい。row多相なので、明示的なコアーションが要る訳でもない。ファクンター適用して使う。
let v1 = let module PV' = PV (struct type p = int z_point end) in PV'.show @@ PV'.add (new z_point ~x:1 ~y:2 ~z:3) @@ PV'.add (new z_point ~x:4 ~y:5 ~z:6) @@ PV'.make ()