次に、同様の作業を参照セルで行ってみます。
let xRef = ref 3;; //※5 参照セルの新規作成 xRef := !xRef + 1;; //※6 xRef;; !xRef;; let yRef = xRef;; //※7 yRef := !yRef + 1;; //※8 yRef;; !yRef;; xRef;; !xRef;;
▼
val xRef : int ref = {contents = 3;}
> val it : unit = ()
>val it : int ref = {contents = 4;}
>val it : int = 4
>val yRef : int ref = {contents = 4;}
>val it : unit = ()
>val it : int ref = {contents = 5;}
>val it : int = 5
>val it : int ref = {contents = 5;}
>val it : int = 5
以下の参照セルの操作のイメージ図を見てください。

xRefにint ref型(参照セル)の3をバインド(※5)します。
※6のxRefの前にある!ですが、参照セルの前に置くことで、参照セルが示す場所にある値を返します。:=は代入演算子で値を変更する際に使用します。
つまり、※6の部分ではxRef1が指す場所にある値3に1を追加し、それをxRefに代入しています。
※7で、yRefにxRefをバインドします。※8では、yRefが指し示す場所(すなわちxRefも指している)にある値を変更します。したがって変更後は、!yRefで読み込まれる値だけではなく、!xRefの値も変更されています。
制約
次に、前回までの連載で説明を省いていた機能制約について説明します。
F#にもC#同様に、ジェネリック型やファンクションで型引数用に要件を指定するために、ジェネリック型のパラメータに適用できる制約という機能があります。
型パラメータリスト when 制約1 [ and制約2]
制約を適用したい型パラメータのリストの後に、whenと制約を追加します。
制約には下記のようなものがありますが、最も使用されるのは型制約で、その他はライブラリによってある機能を実装するために使用されるか、主にCLIでサポートされる一連の制約に対しての互換性のためのものです。
| 制約の種類 | 構文 | 役割 |
| 型制約 | 型パラメータ:> 型 | 型は:>オペレータの後に指定された型を継承するものか同じのものでなくてはならない。インターフェイス型の場合には、そのインターフェイスを実装しなくてはならない |
| Null制約 | 型パラメータ: null | 型はNullに設定されるケースをサポートしなくてはならない。F#のlist、組、関数、クラス、レコード、ユニオン型意外の全ての.NETオブジェクト型を含む |
| 明示的メンバー制約 | 型パラメータ[or ... or 型パラメータ] : メンバーシグネチャ | 最低1つの型引数が指定されたシグネチャを持つメンバーを持つ必要がある。一般的には余り用いられない |
| コンストラクター制約 | 型パラメータ : ( new : unit -> 型 | 型はデフォルトコンストラクターを持つ必要がある |
| 値型制約 | : struct | 型は .NETの値型である必要がある |
| 参照型制約 | : not struct | 型は.NETの参照型である必要がある |
| 列挙型制約 | : enum<ベースとなる型> | 型は指定されたベース型を持つ列挙型である必要がある。一般的には余り用いられない |
| デレゲート制約 | : delegate<組パラメータ型, 戻り値型> | ジェネリック型は指定された引数と戻り値を持つデレゲートである必要がある。一般的には余り用いられない |
| 比較制約 | : comparison | 型は比較機能をサポートする必要がある |
| 等式比較 | : equality | 型は等式機能をサポートする必要がある |
| アンマネージド制約 | : unmanaged | 型はアンマネージ型である必要がある。sbyte, byte, char, nativeint、unativeint、float32、float、int16、uint16、int32、uint32、int64、uint64、decimalなどの基本型、列挙型 nativeptr<_>型や、アンマネージ型のフィールドだけで構成された非ジェネリックの構造体などのいずれかである必要がある |
型制約
以下は、型パラメータの引数として使用できる型に対する制約を指定する、型制約の使用例です。
class GenericList<T> where T : BaseClass
{
:
}
制約により、T型のすべての項目がBaseClassオブジェクト、またはBaseClassから継承されたオブジェクトのいずれかであることが保証されています。
type 'a genericType when 'a :> BaseClass = class : end
F#の構文に従ってwhenと:>を使用して型制約を定義します。
制約により、’a型のすべての項目がBaseClassオブジェクト、またはBaseClassから継承されたオブジェクトのいずれかであることが保証されています。
メンバー制約
次に、メンバー制約について説明します。
メンバー制約は、提供された型パラメータがある種のシグネチャを持つことを保証するためのものです。F#ライブラリでオーバーロードファンクションを定義する際などによく使用されます。オーバーロードファンクションとは、同一名の演算子記号やメソッドを複数定義し、IDなどを使用して区別し、状況に応じて選択して使用させる機能のことです。メンバー制約を有効にするためには、inline修飾子をつけます。
let testMethod1 x = x + x let inline testMethod x = x + x;;
▼
val testMethod1 : int -> int val inline testMethod : ^a -> ^b when ^a : (static member ( + ) : ^a * ^a -> ^b)
例えば、上記リスト7において、inlineなしの場合メンバー制約は有効にはならないため、関数testMethod1は1種類のみ(例:int)の値が対象になります。しかし、inlineを使用した場合はメンバー制約が有効になるので、関数testMethod2は汎用的な関数となり、対象の値はジェネリックになります。
