
Am Dienstag 02 Februar 2010 16:06:52 schrieb Dave Bayer:
test1, test2 ∷ Monad m ⇒ m (a → a) test1 = mcompose unit unit test2 = compose unit unit
-- test2 error: -- Could not deduce (Composable -- (m (a -> a)) (m1 (a1 -> a1)) (m2 (a2 -> a2))) -- from the context (Monad m2) -- arising from a use of `compose' at Issue2.lhs:26:10-27
test3, test4 ∷ Maybe ShowS test3 = mcompose tab tab test4 = compose tab tab
It appears to me that type inference in type classes is broken. How else to explain why mcompose has no trouble figuring out that the monads are the same, but compose is stumped?
Try removing the type signature for test2 and see what that gives: Compose.hs:28:8: No instance for (Composable (m (a -> a)) (m1 (a1 -> a1)) c) arising from a use of `compose' at Compose.hs:28:8-25 Possible fix: add an instance declaration for (Composable (m (a -> a)) (m1 (a1 -> a1)) c) In the expression: compose unit unit In the definition of `test2': test2 = compose unit unit Failed, modules loaded: none. commenting out test2 and querying the type at the prompt: *Compose> :t compose unit unit compose unit unit :: (Monad m, Monad m1, Composable (m (a -> a)) (m1 (a1 -> a1)) c) => c In mcompose, you specified exactly which types to use, in particular that there's only one monad involved. In test2, the type checker must determine the types from scratch. compose :: forall a b c. Composable a b c => a -> b -> c test2 = compose unit unit unit :: forall m a. Monad m => m (a -> a) The type checker can't assume that both unit's in test2 have the same type, so we have two monads (m, m1) and two types (a, a1) which are to be composed to give a third type (c). compose can only work when it knows the types of both arguments. It doesn't know the type of unit (since that's polymorphic), so it can't work with unit. You can help it somewhat by adding more FunDeps to Composable, class Composable a b c | a b → c, a c -> b, b c -> a where compose ∷ a → b → c , then it can work when it knows a) the types of both arguments or b) the type of one argument and the type of the result. Doesn't help with test2, though.