[Haskell-beginners] Monadic composition without throwing
genericity under the bus?
daniel.is.fischer at web.de
Tue Feb 2 11:08:44 EST 2010
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:
No instance for (Composable (m (a -> a)) (m1 (a1 -> a1)) c)
arising from a use of `compose' at Compose.hs:28:8-25
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,
Composable (m (a -> a)) (m1 (a1 -> a1)) 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
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
b) the type of one argument and the type of the result.
Doesn't help with test2, though.
More information about the Beginners