例: カウンタの実装

次のようなオブジェクト指向プログラミング (OOP) スタイルのカウンタオブジェクトの実装を見てみましょう。 カウンタのために型 counter を次のように定義します:

typedef counter = '{ get= () -<cloref1> int , inc= () -<cloref1> void , reset= () -<cloref1> void } // end of [counter]

counter の3つのフィールドはクロージャ関数で、オブジェクトと関連したメソッドに対応しています。 すなわち、カウンタの数値の取得、カウンタの数値を 1 加算、カウンタの数値を 0 にリセットします。 次にカウンタオブジェクトを生成するために、関数 newCounter を定義します。 このオブジェクトはクロージャ関数群を格納したボックス化レコードとして表わされます:

fun newCounter ( // argumentless ) : counter = let val count = ref<int> (0) in '{ get= lam () => !count , inc= lam () => !count := !count + 1 , reset= lam () => !count := 0 } end // end of [newCounter]

それぞれ生成されたカウンタオブジェクトの状態は参照に保存されます。 その参照は対応するオブジェクトを表現するレコードの中の3つのクロージャ関数によってのみアクセスできます。 これは OOP におけるカプセル化に対応しています。

上記のカウンタ実装はどちらかというと良いスタイルではないと、私自身は考えています。 単純に抽象化することで状態の整合性を保護することも可能です。 これより後の章にて、線形抽象型 (ATSでは抽象観型と呼ばれます) を使った別のカウンタ実装を説明します。 この実装で生成されたカウンタは安全に解放されます。