参照とは本質的にヒープに確保されたサイズ 1 の配列です。 手動で解放できない参照の内容を保管するために確保されたメモリであるという意味で、参照は永続的です。 その代わりに、参照はガベージコレクション (GC) を通じてのみ (安全に) 回収されます。
観型 VT が与えられたとき、観型 VT の値への参照の型は ref(VT) です。 利便性のために、ATS では型コンストラクタ ref は抽象として宣言されます。 けれども、次のような定義は可能です:
参照に対する様々な関数インターフェイスを prelude/SATS/reference.sats で見つけることができます。参照を生成するために、次のインターフェイスを持つ関数テンプレート ref_make_elt を呼び出すことができます:
ref_make_elt に対して略記 ref を使うこともできます。 ref_make_elt が呼び出されるといわゆる wrt-効果 が発生する可能性があることを、記号 !wrt が示すことに注意してください。参照を通した読み書きのために、 関数テンプレート ref_get_elt と ref_set_elt を使うことができます。 これらにはそれぞれ次のインターフェイスが割り当てられています:
fun{a:t@ype} ref_get_elt (r: ref a):<!ref> a fun{a:t@ype} ref_set_elt (r: ref a, x: a):<!refwrt> void
典型的に、参照は永続化状態を記録するのに使われます。 例えば、次のコードはそのような例です:
local // #define BUFSZ 128 // val count = ref<int> (0) // in (* in of [local] *) fun genNewName (prfx: string): string = let val n = !count val () = !count := n + 1 var res = @[byte][BUFSZ]((*void*)) val err = $extfcall ( int, "snprintf", addr@res, BUFSZ, "%s%i", prfx, n ) (* end of [$extfcall] *) in strptr2string(string0_copy($UNSAFE.cast{string}(addr@res))) end // end of [genNewName] end // end of [local]
参照の誤用 参照は誤用されることが実際にあります。 次のプログラムは、命令型プログラミングを既に学んだ関数型プログラミングの初学者がしばしば書いてしまうものです:
fun fact (n: int): int = let val res = ref<int> (1) fun loop (n: int):<cloref1> void = if n > 0 then (!res := n * !res; loop(n-1)) else () val () = loop (n) in !res end // end of [fact]
// int fact (int n) { int res = 1 ; while (n > 0) { res = n * res; n = n - 1; } ; return (res) ; } //
fun fact (n: int): int = let fun loop (n: int, res: int): int = if n > 0 then loop (n, n * res) else res // end of [loop] in loop (n, 1) end // end of [fact]
強い正当な理由なしに (動的に生成される) 参照を広範囲にわたる使用することは、しばしば悪いコーディングスタイルの兆しです。
静的に確保された参照 ref_make_elt を呼び出して参照を生成すると、動的なメモリ確保が必要になります。 もしこれが望ましくなかたったり容認できなかったりするなら、 次のように参照の生成に静的なメモリ確保を使うことができます:
関数 ref_make_viewptr はポインタとそのポインタに関連した駐観の証明を取り、その証明を消費した後の参照を返します。 ref_make_viewptr はキャスト関数なので、実行時のオーバーヘッドはありません。 上記のコードでは、myvar は静的に確保されていて、その駐観の証明が ref_make_viewptr によって消費された後ではもはや有効ではありません。 C言語では myvar と myref の両方とも単に同じポインタですが、ATS ではそれらは本質的に異なる概念の具象であることは興味深いでしょう: 前者は線形の値であり、後者は非線形の参照なのです。この章で紹介したコードの全体は オンライン から入手できます。