ATS の型をエクスポートしてC言語から使う

ATS では、ATS の型をエクスポートしてC言語から直接使うこともできます。 次の例では、ATS の (int, string) 型が割り当てられた値のために、 生成されたC言語コード中で int_and_string の名前の typedef が宣言されることを期待しています:

extern typedef "int_and_string" = (int, string)

本質的に int_and_string はC言語の中で次のように定義されます:

typedef
struct {
  int atslab__0; void *atslab__1; 
} int_and_string ;

ときどき、ATS におけるデータ型宣言の値をC言語でコンストラクトしたいことがあります。 例えば、i が整数で d が倍精度実浮動小数点数であるような cons2(i, d) の値をC言語でコンストラクトしてみましょう。 cons2 は次で宣言されたデータ型 abc に関連したデータコンストラクタです:

datatype abc = | cons1 of int | cons2 of (int, double)

データコンストラクタを宣言すると必ず対応する (線形の) 型コンストラクタが作られます。 そのコンストラクタには元のデータコンストラクタの名前と文字列 "_pstruct" を連結した名前が付けられます。 そのため上記で宣言したデータ型 abc の場合は、 型コンストラクタ cons1_pstructcons2_pstruct が作られます。 これらの型コンストラクタはデータコンストラクタ cons1cons2 でコンストラクトされるボックス化された値の型を形成するために使われます。

次の宣言で ATS の cons2_pstruct(int, double) 型が cons2_node の名前でC言語にエクスポートされます:

extern vtypedef "cons2_node" = cons2_pstruct(int, double)

また cons2 データコンストラクタによってコンストラクトされる値のアンボックス部分のために、 cons2_node_ という名前でC言語の typedef が暗黙のうちに導入されます。 結果として次のようなC言語コードが生成されるでしょう:

typedef
struct {
int contag ; // constructor tag
int atslab__0; double atslab__1; 
} cons2_node_ ;
typedef cons2_node_ *cons2_node ;

これでC言語中で直接 cons2(i,d) の値を作るのは簡単でしょう:

cons2_node
cons2_make
(
  int i, double d
) {
  cons2_node p ;
  p = ATS_MALLOC(sizeof(cons2_node_)) ;
  p->contag = 1 ;
  p->atslab__0 = i ;
  p->atslab__1 = d ;
  return p ;
} /* end of [cons2_make] */

cons1cons2 のコンストラクタタグはそれぞれ0と1であることに注意してください。 cons1cons2 はデータ型 abc に関連した1番目と2番目のコンストラクタであることがその理由です。

ATS 側で cons2_make にインターフェイスを割り当てることで、cons2_make の挙動が意図したものかどうかチェックできます:

extern fun cons2_make (int, double): abc = "mac#" val-cons2 (1, 2.34) = cons2_make (1, 2.34)

一般に、低レイヤーのシステムプログラミングにおいてプログラミング言語を使うために、その言語の低レベルのデータ表現をしっかり理解することはプログラマにとって不可欠です。 ATS の低レベルデータ表現はC言語の型の項を使って簡単に解釈できます。 そのため必要であればC言語の中で ATS の値を直接コンストラクトし操作することは容易なのです。