メンバ関数

前回でクラスにフィールドを追加する方法を学んだので 今度はクラスに関数を持たせる方法を説明します。 以前述べたとおり、クラスの持つ関数のことを メソッドまたはメンバ関数などと呼びます。 メンバ関数の定義に相当する構文規則を抜き出したのが 次の部分です
メンバ関数の定義
クラス定義 :=  type クラス名 [ パターン ] [ as 識別子 ] =   class   ...   [要素型定義]*  end 要素型定義 := | メンバ定義  | ... メンバ定義 := | [ static ] member メンバ束縛  | ... メンバ束縛 := | [ 識別子 '.' ] 束縛 | [ 識別子 '.' ] 識別子 with 束縛
構文だけみてもわかりにくいと思うので 3つのメンバ関数(と1つのプロパティ) を定義した例を挙げてみます。
メンバ関数の定義
open System;;
type ClassWithMember = class
    val mutable data : int
    new (init) = {data = init;}
    member x.show _ = Console.WriteLine(x.data)
    member x.addshow y = Console.WriteLine(x.data + y)
    member x.update input = x.data <- input
    member x.prop = 10
    end;;
let obj = new ClassWithMember(10) in
obj.show();
obj.addshow(10);
obj.update(100);
obj.show();
obj.addshow(10);
Console.Write(obj.prop);;
memberがメンバを宣言する際のキーワードです。 それに引き続いて 自分自身の参照名.メンバ関数名 パターン1 ...=関数本体 という形で関数を定義します。 memberキーワードと自分自身の参照名があることを除けば これは通常の関数定義と変わりはありません。 もちろん、メンバ関数はカリー化することも出来るし 別の変数に代入することも出来ます そして、関数呼び出しは、オブジェクト名.メンバ関数名とします。 自分自身の参照名というのは、 関数の定義の本体から 自クラス内で定義されているメンバにアクセスするためのもので 通常はxやvなどの短い名前か thisやselfといった名前を用います。 この例ではxとなっているため x.dataとすることでdataメンバの値を参照することが出来ます。 また、propメンバのように、仮引数のないメンバがいてもかまいません

staticなメンバ関数

メンバ関数は基本的にオブジェクトを通じて呼び出しますが staticキーワードをつけて宣言した場合 クラスを通して呼び出すことが出来ます。 そのため、関数を宣言する際に 自分自身を参照する名前をつける必要はありません。 これは、例えば数学用のクラスのような 具体的なオブジェクトが必要ないようなクラスで よく利用されます。 以下の例では、絶対値を返すstaticなメンバ関数を持つ 非常に簡単なMathクラスを定義しています。
staticなメンバ関数
type Math = class
    static member abs v = if v<0 then -v else v
    end;;
let a = Math.abs(-10) in
System.Console.WriteLine(a);;
このように、staticなメンバ関数を呼び出す際は クラス名.関数名とすることで呼び出すことが出来ます。

オブジェクトとしてのレコード

レコード型の説明の箇所では説明しませんでしたが レコードはフィールドの他にメンバ関数も持つことが出来ます。 これにより、レコードを用いて オブジェクトをエミュレートすることが出来ます。 レコードにメンバ関数を定義するには次の構文を用います。 メンバ関数名の前の型名は、 クラスの時と同じく自分自身を参照するための名前です。
メンバ関数付きレコードの定義
type 型名 = { フィールド名1 : 型名1; ... ; フィールド名n : 型名n } with member 型名1.メンバ関数名1 パターン1 ... パターンn = 本体 .. member 型名n.メンバ関数名n パターン1 ... パターンn = 本体 end
これを用いて、 点の座標を表すレコードを作成してみます。
Point型の利用
type Point = {mutable x : int; mutable y : int}
    with
        member v.move (p:Point) =
            v.x <- v.x + p.x;
            v.y <- v.y + p.y;
        member v.show _=
            System.Console.WriteLine ("x=" ^ v.x.ToString() ^ ",y=" ^ v.y.ToString())
    end;;
let p = {x=10;y=10} in
let move_vector = {x=100;y=100} in
p.show();
p.move(move_vector);
p.show();;
Point型はxとyの値を持つだけの単純なデータ型で フィールドの値を表示するshowメソッドと 別のPoint型を(移動するベクトル量として)受け取るmoveメソッドを持っています。 この例の通り、メンバ関数へのアクセスは フィールドへのアクセスと同じくドット記法を用います。