特殊テンプレート実装

関数テンプレートのインターフェイスを特殊実装するというのは、 そのテンプレートの固定のインスタンスに実装を与えることです。 例えば、次のインターフェイスは eq_elt_elt という名前の関数テンプレートです:

fun{a:t0p} eq_elt_elt (x: a, y: a): bool // a generic equality

型 T の等値性検査は型 T に依存するので、 eq_elt_elt の意味のある総称的な実装は存在しません。 2つの特殊テンプレート実装である インスタンス eq_elt_elt<int>eq_elt_elt<double> を次に示します:

implement eq_elt_elt<int> (x, y) = g0int_eq (x, y) implement eq_elt_elt<double> (x, y) = g0float_eq (x, y)

eq_int_inteq_double_double はそれぞれ intdouble 型の値に対する等式関数です。 この実装は次のように書くこともできます:

implement eq_elt_elt<int> (x, y) = (x = y) implement eq_elt_elt<double> (x, y) = (x = y)

シンボル =g0int_eqg0float_eq でオーバーロードされている (その他多くの関数もオーバーロードしていています)ので、 このような実装が可能なのです。

ここで、特殊テンプレート実装の典型的な使い方を見てみましょう。 次に定義する関数テンプレート listeq はリストの等式関数を実装しています:

fun{ a:t0p } listeq ( xs: list0 a , ys: list0 a ) : bool = ( case+ (xs, ys) of | (list0_cons (x, xs), list0_cons (y, ys)) => if eq_elt_elt<a> (x, y) then listeq (xs, ys) else false | (list0_nil (), list0_nil ()) => true | (_, _) => false ) (* end of [listeq] *)

2つのリスト xs と ys が与えられた時、xs と ys が同じ長さでなおかつそれぞれの要素が等しい (eq_elt_elt を使って比較することになります) なら listeqtrue を返します。 型 T が与えられた時、list0(T) 型の2つのリストに対して listeq を使うために、eq_elt_elt<T> のインスタンスが必要になることは明らかです。 別の言い型をすると、list0(T) 型の2つのリストに listeq を呼び出すのであれば、eq_elt_elt<T> の特殊実装を与える必要があるのです。 関数テンプレートのインスタンス実装は、インスタンスを呼び出すファイルで有効でなければならないことに注意してください。

比較のために、与えられた2つのリストが等しいか判定する関数テンプレート listeqf を次に実装します:

fun{ a:t0p } listeqf ( xs: list0 a , ys: list0 a , eq: (a, a) -> bool ) : bool = ( case+ (xs, ys) of | (list0_cons (x, xs), list0_cons (y, ys)) => if eq (x, y) then listeqf (xs, ys, eq) else false | (list0_nil (), list0_nil ()) => true | (_, _) => false ) (* end of [listeqf] *)

この例では listeqf には、リストの要素同士が等しいか判定するために引数 eq が追加されています。 listeqf は高階関数ですが listeq は通常の関数なので、 前者はより効率的なオブジェクトコードにコンパイルされる可能性が高いことになります。 また、ATS のライブラリでは特殊実装のテンプレートを広範囲に使っています。

この章で示したコードとテストのための追加コードは オンライン から入手できます。