Concurrent Clean : 型クラスとクラスコンテキスト
classに付けられたクラスコンテキストと、instanceに付けられたクラスコンテキストでは意味が違う。
class Measured a v | Monoid v where measure :: a -> v
という宣言は、単に、Measuredクラスに属する型は、Monoidクラスにも属していますということを言っているに過ぎない。そのため、
instance Measured Int v where measure _ = zero
と書こうとしても、zero関数がコンテキストで与えられていないために失敗する。
instance Measured Int v | Monoid v where measure _ = zero
と書かなければならない。(無駄な指定を行っているように見えるが、そういうルールである)
これは、instanceに付加されたクラスコンテキストは、
instance Measured Int v | Monoid v where measure :: Int -> v | Monoid v measure _ = zero
というように展開されて解釈されるのに対し、classに付加されたクラスコンテキストは、そのようには解釈されないためである。
この制限は、次のようなケースでより顕著となる。
class A a b where g :: a -> b h :: a -> b instance A a Int | toInt a where g a = toInt a h a = g a
というように、h関数からg関数を呼び出そうとした場合、コンパイルエラーとなる。これは、h関数の型にAクラスのコンテキストが付加されていないため、g関数がコンテキストから取得できないためである。
ややこしい。