pick ADT
styxlibの話に入る前にpickについて書いておく。メッセージパッシングのプログラムでは、メッセージをあるフォーマットのデータ構造にpack/unpackする必要があるが、pickはそんなときに便利な機能だ。Cでは、構造体の先頭にメッセージの種類(or タグ)を格納しておいて、その後にunionを使って、種類ごとに異なるデータ構造が続く。LimboにはCのunionのようなpickという構文がある。以下では説明のために、一つのpickと関数からなるApick ADTを宣言する*1。Apickの各タグ(Stirng、Int、Real)は一つのメンバしかもっていないが、もちろん複数のメンバを持つことができる。
Apick : adt {
pick {
String => val: string;
Int => val: int;
Real => val: real;
}
printeval : fn(this : self ref Apick);
};ここでpickへの書き込みは次の通り。
r := ref Apick.Real;
r.val = 3.14;
s := ref Apick.String("Hello, World!");
# s := ref Apick.String; s.val = "Hello, World!"でもOK関連して、LimboにはCにはないtagof演算子がある。これは与えられたリファレンスがpick ADTの何番目のタグか返す。上の例では"tagof s"は0、"tagof r"は2となる。tagofを使って、Apickリファレンスの型名を返す関数を定義してみる。
tag(t : ref Apick): string
{
r: string;
case tagof t {
tagof Apick.String => r = "String";
tagof Apick.Int => r = "Int";
tagof Apick.Real => r = "Real";
}
return r;
}最期にpick文を使った、printval関数を見てみよう。pick文はcaseに似ているが、ラベルとしてpickの要素を指定する。
Apick.printval(this: self ref Apick)
{
pick t := this {
String => sys->print ("%s: %s\n", tag(t), t.val);
Int => sys->print ("%s: %d\n", tag(t), t.val);
Real => sys->print ("%s: %f\n", tag(t), t.val);
}
}*1:説明のコードはInfernoのマニュアルから。