ボックス化 されたタプル/レコードは、フラットなタプル/レコードが保管されたメモリ位置への単なる参照です。 しばしばフラットなタプル/レコードを表現するのに、アンボックス化 という用語も使われます。
次のコードでは、型 abc_tup と abc_rec はそれぞれボックス化タプルとボックス化レコードを表わしています:
typedef abc_tup = '(int, int, string) // for tuples typedef abc_rec = '{a=int, b=int, c=string} // for records
typedef abc_tup = $tup(int, int, string) // for tuples typedef abc_rec = $rec{a=int, b=int, c=string} // for records
次のコードはタプルとレコード生成し、それらの要素 (すなわちフィールド) を取り出す方法を示しています:
// val x_tup = '(0, 1, "2") : abc_tup val x_rec = '{a=0, b=1, c="2"} : abc_rec // val ((*void*)) = assertloc(x_tup.0 = x_rec.a) val ((*void*)) = assertloc(x_tup.1 = x_rec.b) val ((*void*)) = assertloc(x_tup.2 = x_rec.c) //
x_tup と x_rec は両方とも不変であることには注意すべきでしょう。 もし次のコードを型検査すると、x_tup.0 と x_rec.a が左辺値ではないというエラーになります:
// val () = x_tup.0 := 100 // *ERROR*: x_tup.0 not a left-value val () = x_rec.a := 100 // *ERROR*: x_tup.0 not a left-value //
可変フィールドのタプル/レコードを得るためには、フラットなタプル/レコードへの参照を作るだけです。 次のコードでは、フラットなタプルとレコードを表わす型 abc_tup_ と abc_rec_ をそれぞれ宣言しています:
// typedef abc_tup_ = @(int, int, string) // for tuples typedef abc_rec_ = @{a=int, b=int, c=string} // for records //
// typedef abc_tup_r = ref(abc_tup_) // for tuples typedef abc_rec_r = ref(abc_rec_) // for records //
// val x_tup_r = ref<abc_tup_>(@(0, 1, "2")) val x_rec_r = ref<abc_rec_>(@{a=0, b=1, c="2"}) // (* ****** ****** *) // val () = assertloc(x_tup_r->0 = x_rec_r->a) val () = assertloc(x_tup_r->1 = x_rec_r->b) val () = assertloc(x_tup_r->2 = x_rec_r->c) // (* ****** ****** *) // val () = x_tup_r->0 := 100 // *OKAY*: x_tup_r.0 is a left-value val () = x_rec_r->a := 100 // *OKAY*: x_rec_r.a is a left-value //
あるフィールドが読み出しのみで他のフィールドは更新できるような型のレコードが欲しいなら、ATS の抽象型のサポートを使うことで実現できます。 次の例では、myrec は抽象的に宣言されています; myrec に関連した3つのフィールドがあり、それらは名前 a, b, c です; 最初の2つは更新可能であるが、3つめは読み出ししかできません:
(* ****** ****** *) abstype myrec = ptr (* ****** ****** *) // extern fun{} myrec_make ( a: int, b: int, c: string ) : myrec // end-of-function // extern fun{} myrec_get_a : myrec -> int extern fun{} myrec_set_a : (myrec, int) -> void extern fun{} myrec_get_b : myrec -> int extern fun{} myrec_set_b : (myrec, int) -> void extern fun{} myrec_get_c : myrec -> string // overload .a with myrec_get_a overload .a with myrec_set_a overload .b with myrec_get_b overload .b with myrec_set_b overload .c with myrec_get_c // (* ****** ****** *) local // assume myrec = abc_rec_r // in (* in-of-local *) // implement {}(*tmp*) myrec_make (a, b, c) = ref(@{a=a, b=b, c=c}) // implement{} myrec_get_a(x) = x->a implement{} myrec_set_a(x, a) = x->a := a // implement{} myrec_get_b(x) = x->b implement{} myrec_set_b(x, b) = x->b := b // implement{} myrec_get_c(x) = x->c (* // // there is no update for the c-field: // implement{} myrec_set_a(x, c) = x->c := c *) // end // end of [local] (* ****** ****** *)
// val x_abc = myrec_make(0, 1, "2") // val ((*void*)) = assertloc(x_abc.a() = 0) val ((*void*)) = assertloc(x_abc.b() = 1) val ((*void*)) = assertloc(x_abc.c() = "2") // val ((*void*)) = x_abc.a(100) val ((*void*)) = assertloc(x_abc.a() = 100) // val ((*void*)) = x_abc.b(101) val ((*void*)) = assertloc(x_abc.b() = 101) // (* val ((*void*)) = x_abc.c("102") // *ERROR*: unsupported *) //
この章で使ったコードとテストコードの全体は オンライン から入手できます。