Chapter 7. モジュール性

Table of Contents
仕様としての型
ATS の静的/動的ファイル
総称テンプレート実装
特殊テンプレート実装
抽象型
例: 有理数パッケージ
例: ファンクタを用いた有理数パッケージ

一般的に言って、プログラミングにおけるモジュール性とは、モジュールスタイルでプログラムを組織化することです。 そのスタイルとは、モジュールそれぞれがある作法で分離されて構築されていて、 一貫した方法で機能を形作ることです。 この章では ATS における、大きなプログラムの組織化を容易にするいくつかの機能を紹介します。

この章で紹介するコードとテストのためのいくつかの追加コードは オンライン から取得できます。

仕様としての型

関数や値に対するインターフェイスは、その関数や値の実装が有するべき型を特定します。 例えば、次のコードは与えられた整数の階乗を計算する関数 fact を定義しています:

fun fact (x: int): int = if x > 0 then x * fact (x-1) else 1

最初に考えられる fact のインターフェイス定義は次のようなものでしょう:

extern fun fact (x: int): int

extern は、インターフェイスの宣言を開始する ATS のキーワードです。 fact のインターフェイスを宣言する別の方法は次のようなものです:

extern fun fact : (int) -> int extern val fact : (int) -> int

もし fact が関数として宣言されたなら、 コード中で使うには適用させる必要があります。 もし値として宣言されたのであれば、そのような制約はありません。

関数インターフェイスは仕様だと考えることができます。 例えば、fact に対する上記のインターフェイスは、fact が整数の引数を1つ取り、整数であることが保証された値を返す関数であることを指定しています。 この仕様の形式の特殊な点は、ATS の型検査によって強制されるということです: ATSにおける正しく型付けされた fact の実装はそのような宣言のインターフェイスを持たなければなりません。 もちろん、この fact のインターフェイスは厳格な仕様でありません。 同じインターフェイスを持つ多くの (場合によっては無限に) 関数実体が存在するからです。 けれどもこの一種の不正確性は、時に軽減したり除去することさえできます。 依存型を説明した後で、次の2つの等式で定義される階乗の関数を正確にインターフェイスの実装とすることを保証するような fact のインターフェイスを紹介しようと思います:

次に示す fact の実装は fact で宣言したインターフェイスを守っています:

implement fact (x) = if x > 0 then x * fact (x-1) else 1

implement キーワードは、既にインターフェイスを宣言された関数や値の実装の開始を表わします。 ATS 初心者にとっては、次のコーディングスタイルがより一般的かもしれません:

implement fact (x: int): int = if x > 0 then x * fact (x-1) else 1

この実装は型検査を通りますが、にもかかわらず悪いスタイルと言えます。 fact の引数と返値にプログラマが与えた型は、 型検査器によって自動的に合成されるため、冗長です。

値に対するインターフェイスの例として、 型 int の値である fact10 を次に宣言してみます:

extern val fact10 : int

次に示す fact10 の実装は fact10 で宣言したインターフェイスを守っています:

implement fact10 = fact (10)

別の例として、次のコードでは swap_boxed という名前で多相関数のインターフェイスを宣言しています:

extern fun swap_boxed{a,b:type} (xy: (a, b)): (b, a)

型変数 ab はボックス化されていることに注意してください。 swap_boxed の実装は次のようになるでしょう:

implement swap_boxed{a,b} (xy) = (xy.1, xy.0)

{a,b} という構文は、静的な変数 abswap_boxed に同時に渡しています。 ab も実際には swap_boxed の中身では使われないので、 この場合 {a,b} は省くことができます。

また別の例として、 次のコードは swap_tmplt という名前で関数テンプレートのインターフェイスを宣言しています:

extern fun{a,b:t@ype} swap_tmplt (xy: (a, b)): (b, a)

型変数 ab は種 t@ype であることに注意してください。 これらの型変数がどのようなサイズも取れることを示しています。 swap_tmplt の実装は次のようなものでしょう:

implement{a,b} swap_tmplt (xy) = (xy.1, xy.0)

実際に関数を実装する前に、 パッケージでサポートすべき関数のインターフェイスをデザインすることは、プログラマにとって一般的な訓練です。 そのようなインターフェイスがあれば、 そのインターフェイスデザインが妥当で実際に使いやすいかどうか検査するために、 アプリケーションプログラムを作ることができます。 貧弱なデザインを持つ素晴しい実装は良いデザインを作りえないということを、覚えておいてください。 したがって、実際に実装する前にデザインを検査することはしばしば非常に重要になります。 複雑なデザインが入り組んでいる時には、特に重要です。