8.6 オブジェクトの表現
レコードは種々のデータ構造の定義の基本であり,データベースや オブジェクト指向プログラミングなどで使われています. 第12章で詳しく説明する通り,多相レコー ド操作を基本に,データベースの問い合わせ言語SQLを完全な形でML言語内にシー ムレスに取り込むことができます. オブジェクト指向プログラミングに関しては,計算モデルが異なるため, その機能を完全に表現することはできませんが,オブジェクトの操作に関しては, 多相型レコードで表現できます.
オブジェクトは,状態を持ち,メソッドセレクタをメッセージとして受 け取り,オブジェクトの属するクラスの対応するメソッドを起動し状態を更新し ます. クラスは,メッセージによって選び出されるメソッド集合ですから,関 数のレコードで表現できます. 各メソッド関数は,オブジェクト状態を受け取りそれを更新するコード です. 例えば, X座標, Y座標, Color属性 を持ち得る pointClass のオブジェクト表現を考えてみましょう. オブジェクトは,例えば{X = 1.1, Y = 2.2}のようなレコード への参照を内部に持つとします. すると,各メソッドはこのオブジェクトをselfとして受け取り更 新する関数と表現できます. 例えばX座標に新しい値をセットするメソッドは,以下のように コードできます.
# fn self => fn x => self := (!self # {X = x});
val it = fn : [’a#{X: ’b}, ’b. ’a ref -> ’b -> unit]
このメソッドは,Xを含む任意のオブジェクトに適用できます. これらメソッドにメソッド名を付けてレコードにしたものをクラスと考 えます. 例えば,pointClassは以下のように定義できます.
val pointClass =
{
getX = fn self => #X (!self),
setX = fn self => fn x => self := (!self # {X = x}),
getY = fn self => #Y (!self),
setY = fn self => fn x => self := (!self # {Y = x}),
getColor = fn self => #Color (!self),
setColor = fn self => fn x => self := (!self # {Color = x})
}
オブジェクトは,メッセージを受け取り,このクラスの中からメソッド スイートの中から,対応する関数を選択し自分の状態に適用する関数です. 関数を値として使用できるMLでは,以下のようにコードできます.
local
val state = ref {X = 0.0, Y = 0.0}
in
val myPoint = fn method => method pointClass state
end
Color属性をもつオブジェクトも同様です.
local
val state = ref {X = 0.0, Y = 0.0, Color = "Red"}
in
val myColorPoint = fn method => method pointClass state
end
この定義の下で,以下のようなオブジェクト指向スタイルのコーディン グが可能です.
# myPoint # setX 1.0;
val it = () : unit
# myPoint # getX;
val it = 1.0 : real
# myColorPoint # getX;
val it = 0.0 : real
# myColorPoint # getColor;
val it = "Red" : string
# myPoint # getColor;
(interactive):15.1-15.12 Error:
(type inference 007) operator and operand don’t agree
...
最後の例のように,完全な静的な型チェックも保証されています.