ATS における関数テンプレートのサポートは ATS のデザインと実装に深く根差しています。 第一に、関数テンプレートは ATS におけるコード再利用の一般的なアプローチを提供しています。 それは (妥当性の面で) とても柔軟で、必要になる実行時オーバーヘッドは最小のものです。 ATSPRE (つまり ATSLIB/prelude) と ATSLIB/libats の両方はテンプレートに基いていて、atsopt によって吐き出されるC言語コードが ATS ソースコード中のテンプレート実体を実装するためにそれらのライブラリにおけるテンプレートは使われます。 リンクする ATS のライブラリファイル (libatslib.a と libatslib.so) は最小のものです。 それらは ATS ソースコードを実行バイナリにコンパイルするのに不要なことさえあります。
この章で紹介するコードとテストコードは オンライン から入手できます。
この本の I 章で概説した通り、ネイティブのアンボックス化されたデータの存在下におけるパラメータ多相に関する問題に対して、関数テンプレートは自然な解決策です。 けれども、関数テンプレートはパラメータ多相の単なるサポートより多くのことが可能です。 myprint が次のインターフェイスの関数テンプレートだとしましょう:
値が与えられたとき、myprint はこの値に対するなんらかの表現を印字するものとしましょう。 例えば、myprint を次のように実装できます: myprint のこの実装はしばしば (完全な) 総称テンプレート実装と呼ばれます。 そのテンプレートパラメータに何の制限も課されていないからです。 次のように同じ実装を書く別の方法もあります: 明らかに、上記 myprint のジェネリックス実装は、与えられた値について特別な情報を何も印字できないという点において十分ではありません。 型 int の値のみをサポートする myprint を実装したくなるかもしれません: このとき print_int は与えられた整数を印字します。 myprint のこの実装は特殊テンプレート実装としばしば呼ばれます。 テンプレートパラメータに特別な型 (つまりこの例では int) を割り当てているからです。 次のコードは、リスト値 (つまりなんらかの型 T に対する型 List(T) の値) のための myprint を実装しています:implement(a) myprint<List(a)> (xs) = case+ xs of | list_nil () => () | list_cons (x, xs) => (myprint<a> (x); myprint<List(a)> (xs))
(* ** The output is "0123401234" *) val ys = $list{int}(0,1,2,3,4) val yss = $list{List(int)}(ys, ys) val ((*void*)) = myprint<List(List(int))> (yss) val ((*void*)) = print_newline((*void*))
関数テンプレートの実装はある特定の順序に従って順序付けられます。 これはジェネリックス順序 (genericity ordering) と呼ばれます: もし、ある実装が別の実装のインスタンスであるなら、前者のジェネリックスは後者のジェネリックス以下になります。 与えられたテンプレートインスタンスをコンパイルするのに必要なテンプレート実装の配置には (best-fit ではなく) first-fit 戦略が取られることに注意してください。 より具体的には、特殊テンレプートインスタンスに対するテンプレート実装の配置では、使用可能な最初の1つを探すのにレキシカルスコープの原理に従っています。
実際には、テンプレートインスタンスに対するテンプレート実装の配置にはほんの少し巧妙な点があります。 myprint2 を次のようなインターフェイスを持つ関数テンプレートとしましょう:
次のコードは myprint2 の部分的な総称テンプレート実装です:// implement(a) myprint2<List(a)> (xs) = case+ xs of | list_nil () => () | list_cons (x, xs) => (myprint<a> (x); 1 + myprint2 (xs)) //
// implement(a) myprint2<List(a)> (xs) = case+ xs of | list_nil () => () | list_cons (x, xs) => (myprint<a> (x); 1 + myprint2<List(a)> (xs)) //
// implement(a) myprint2<List(a)> (xs) = let // fun aux (xs: List(a)): int = // case+ xs of | list_nil () => 0 | list_cons (x, xs) => (myprint<a>(x); 1 + aux(xs)) // in aux (xs) end // end of [myprint2<List(a)>] //
この章で紹介したコード全体とテストコードを含む myprint.dats はオンラインから入手できます。