3.13 関数型オブジェクト

インスタンス変数への代入を使わない point クラスを定義することもできます。 {< ... >} 構文は「自分自身」(すなわち現在のオブジェクト)の、一部のインスタンス変数の値を変更したコピーを返します。

#class functional_point y =
   object 
     val x = y
     method get_x = x
     method move d = {< x = x + d >}
   end;;
class functional_point :
  int ->
  object ('a) val x : int method get_x : int method move : int -> 'a end

#let p = new functional_point 7;;
val p : functional_point = <obj>

#p#get_x;;
- : int = 7

#(p#move 3)#get_x;;
- : int = 10

#p#get_x;;
- : int = 7
    

型略記 functional_point が再帰的であることに注意して下さい。このことは functional_point のクラス型からも見て取れます。自身の型を 'a とし 'amove メソッドの型に現れています。

上の functional_point の定義は次と同値ではありません。

#class bad_functional_point y =
   object 
     val x = y
     method get_x = x
     method move d = new bad_functional_point (x+d)
   end;;
class bad_functional_point :
  int ->
  object
    val x : int
    method get_x : int
    method move : int -> bad_functional_point
  end
    

どちらのクラスに属するオブジェクトも同じ振舞をしますが、子クラスのオブジェクトは違った振舞をします。後者の子クラスでは、 move メソッドは親クラスのオブジェクトを返します。反対に、前者の子クラスでは、move メソッドは子クラスのオブジェクトを返します。

ここで紹介した関数型更新は、 5.2.1 節「文字列 」で紹介するようにバイナリメソッドと組み合わせてよく用いられます。