読者です 読者をやめる 読者になる 読者になる

オブジェクトを使うと普通に便利なこと

オブジェクト使うと便利なこと - soutaroにっき

以前書いた記事は、まあ冗談みたいなものなんですが、ふと本当にオブジェクトの有り難みを感じることがあったのでそれを書く。

OCamlのクラスでは、自分で型を明示的に書いてあげることで多相メソッドを実現できるようになっている。

class a = 
  object (self)
    method id : 'a . 'a -> 'a = fun x -> x
  end
end

上のidというメソッドは、多相型を持つメソッドで、こういうのを「多相メソッド」と言う。こういうメソッドの型は推論できないわりに、普通にOOしようとすると頻繁に出てくるので、うっかり書いてしまうと推論できずに「うがーーーー」ってなるので、こういうのがOCamlのオブジェクトがいまいち使えないものになっている遠因になっていると思う。ただし、型を手で書いてあげさえすれば、多相的なメソッドを定義できるようになっている、というのがここでのポイント。

また、OCamlのオブジェクト中ではselfは単相型を持つことになっているというのがもう一つの制限。この制限は「再帰的に定義されたいくつかの値の中から、別の値を参照するときには、単相型になってしまう」という制限である(polymorphic recursionできない制限)。

let rec id x = x
and f () = id 1 
and g () = id true

この例は適切ではないんだけど(本質的には相互再帰してないから)、ここでid trueで型エラーになるのと同じ問題。そういうわけでオブジェクト中ではselfは再帰的に定義されているんだけど、そのself自体を多相的に使うことはできない、というワケ。こちらの制限は、あんまり引っ掛かることは無いんだけど、ずらずら長い相互再帰する関数群を書いていてふと継続を渡すような関数を書くと、この罠にかかって「うぎゃーーーー」ということになる。そういうわけで、Obj.magic便利ですねまあη変換だったかいうのをやって、継続渡しする関数を事前に定義して、引数に再帰する関数を渡す、みたいなことをすれば良いんだけど、いろいろな事情でそれがめんどくさいのでObj.magic便利ですねこともある。


さて、ここで書いたpolymorphic recursionできない制限が問題になっていたプログラムがあって、Obj.magic便利ですね、とかやってたんだけど、さっきbus error出まくっていらっと来たので、ちょっとちゃんと気合を入れてη変換するかと思ったんだけど、良く考えてみれば、オブジェクトというかクラスを使えば、polymorphic recursionできることに気づいた、という話。いや、これ便利だ。

class a = object (self)
  method id : 'a . 'a -> 'a = fun x -> x
  method f : self#id 1
  method g : self#id true
end


あと他にもモジュール使ってpolymorphic recursionする方法があったような気がするけど、良く覚えてない。module recすれば良いんだっけ。