HaskellとJavaの対応

Comparableインターフェイスは言語的にはcompareToメソッドの存在を保証しているだけだけど、意味をなすためにはユーザが守るべきいくつかの制約がある。

  • 1. 反射律(reflexivity): 任意の元 a について a ≤ a 。
  • 2. 推移律(transitivity): a ≤ b かつ b ≤ c ならば a ≤ c 。
  • 3. 反対称律(antisymmetry): a ≤ b かつ b ≤ a ならば a = b 。

http://ja.wikipedia.org/wiki/%E9%A0%86%E5%BA%8F%E9%9B%86%E5%90%88

compareToを使って le(a, b) = (a.compareTo(b) <= 0)ってのを作っておけば::

  • 1. assert le(a, a)
  • 2. if(le(a, b) && le(b, c)){ assert le(a. c); }
  • 3. if(le(a, b) && le(b, a)){ assert a.compareTo(b) == 0; }

「比較可能なもの」を作る上で、コンパイラが保証できるのは「比較する関数(≤)の存在」までで、その関数が適切な実装のされ方をしているかどうかは言語のユーザが保証しないといけない。その「適切」の基準が上に書いたような反射律・推移律・反対称律の3条件を満たすこと。

モナドクラスも同じで、コンパイラが保証するのはbind(>>=)とreturnの存在だけ。そして同じように満たすべき条件がある。

  • 1. (return x) >>= f == f x
  • 2. m >>= return == m
  • 3. (m >>= f) >>= g == m >>= (\x -> f x >>= g)

http://www.sampou.org/haskell/a-a-monads/html/laws.html

bindがわかりにくいので書き換えると::

  • 1. (bind (return x) f) == (f x)
  • 2. (bind m return) == m
  • 3. (bind (bind m f) g) == (bind m foo) ただし foo は foo x = (bind (f x) g)) になる関数

という感じ。
コンパイラが保証してくれるのはあくまで入れ物の形だけであって、その中身がどういう条件を満たすべきかという仕様がべつにある。こういうのをデザインパターンっていうんじゃないのかな??