... is a rigid type variable bound by ...
なんでこれがエラーになるのかわからないのは、まだなにか理解出来ていことがあるってことなんだろうな。
class Foo a where foobar :: (Bar b) => a -> b class Bar a newtype AFoo = MakeAFoo {foo_value :: Int} newtype ABar = MakeABar {bar_value :: Int} instance Foo AFoo where foobar x = MakeABar $ foo_value x instance Bar ABar
Couldn't match expected type `b' against inferred type `ABar' `b' is a rigid type variable bound by the type signature for `foobar' at tmp.hs:6:19 In the expression: MakeABar $ foo_value x In the definition of `foobar': foobar x = MakeABar $ foo_value x In the definition for method `foobar'
ああ、なるほど。「(Bar b) => 」は「bがBarのインスタンスの *いずれか* である」という意味ではなく「Barのインスタンスである *任意の* bである」という意味になるので、具体的なBarのインスタンスABarを返してはいけない。なぜなら別のBarのインスタンスAnotherBarしかとらない関数にfoobarの返り値を渡すことが型推論上はvalidなのに、実行時に型が違ってエラーが起きてしまう。
class Foo a where foobar :: (Num b) => a -> b newtype AFoo = MakeAFoo {foo_value :: Int} instance Foo AFoo where foobar x = 1
これはOK。なんで?ああ、リテラルの1の型が(Num a) => aなのか?
class Foo a where foobar :: (Show b) => a -> b newtype AFoo = MakeAFoo {foo_value :: Int} instance Foo AFoo where foobar x = "1"
これは期待通りrigid type variableのエラーになる
で、どうやって解決するんだ?