参照はたった1つの要素を持つ配列です。 ある型 T が与えられた時、型Tの値を保管する参照は型 ref(T) になります。 次のプログラムは参照の本質的な機能をすべて利用しています:
val intr = ref<int> (0) // create a ref and init. it with 0 val () = !intr := !intr + 1 // increase the integer at [intr] by 1
reference.sats ファイルでは、参照にまつわる様々な関数と関数テンプレートが宣言されています。 このファイルは atsopt によって自動的に読み込まれます。 特に、次のインターフェイスの関数テンプレート ref_get_elt と ref_set_elt を使うことで、 参照の読み書きをすることもできます:
fun{a:t@ype} ref_get_elt (r: ref a): a // !r fun{a:t@ype} ref_set_elt (r: ref a, x: a): void // !r := x
実際には参照は誤用されがちです。 とりわけC言語や Java のような命令型プログラミング言語に成熟した関数型プログラミングの初心者に見られます。 そのようなプログラマはしばしばC言語や Java で書かれたプログラムを、 関数型プログラムに単に "翻訳" しようと考えます。 次で定義している sumup はそのような例です。 この関数1から与えられた整数までの整数値をすべて加算します:
fun sumup (n: int): int = let val i = ref<int> (1) val res = ref<int> (0) fun loop ():<cloref1> void = if !i <= n then (!res := !res + !i; !i := !i + 1; loop ()) // end of [loop] in loop (); !res end // end of [sumup]
関数型プログラミングにおける参照は危険な機能であると、私は考えています。 もしGCを使わないプログラムを実行したいのであれば、 関数の中で参照を生成してはいけません (その他にも多くの制約があります)。 もし手続型のプログラムを関数型のプログラムに "翻訳" する際に参照が必要になってしまったら、 多くの場合あなたは迷子になっており、関数型スタイルのプログラミングをまだよく学習していないことになります。