I have a type class
class (Monad f) => Test f where
test :: () -> f ()
and an instance
instance Test (ErrorT String (Identity)) where
test pat = return pat
If I run a monad stack referring to this instance, GHC can't find out what monad I am talking about (in a do
block of the Either String
monad):
rhs' <- runIdentity $ runErrorT $ test rhs
yields the error message:
Ambiguous type variable `f0' in the constraint:
(Test f0) arising from a use of `test'
...
But if I bind the part test rhs
to a variable:
let action = test rhs
rhs' <- runIdentity $ runErrorT $ action
it works, even though the variable is used nowhere else so nothing new can be inferred about it.
How is this possible, if I have added no information for the type checker to use? Why can't it figure out the type of the equivalent first formulation? Or are the two formulations not equivalent? What part of the Haskell type checker (or desugaring rules?) did I not understand here?
I am using the extensions MultiParamTypeClasses
, FlexibleInstances
and ScopedTypeVariables
edit: I simplified the example so the strange issue occurs without needing the rest of my code (and with a shorter monad stack), but now it looks nonsensical. The full context of the statement is:
doStuff :: (Map Int ()) -> Either String (Map Int ())
doStuff g = run (snd . head . Map.toList $ g) g where
run :: () -> Map Int () -> Either String (Map Int ())
run rhs g = do
let action = test rhs
rhs' <- runIdentity $ runErrorT $ test rhs -- or: action
return g
The code
doStuff :: (Map Int ()) -> Either String (Map Int ())
doStuff g = run (snd . head . Map.toList $ g) g where
run :: () -> Map Int () -> Either String (Map Int ())
run rhs g = do
rhs' <- runIdentity $ runErrorT $ test rhs
return g
or
doStuff :: (Map Int ()) -> Either String (Map Int ())
doStuff g = run (snd . head . Map.toList $ g) g where
run :: () -> Map Int () -> Either String (Map Int ())
run rhs g = do
let action = test rhs
rhs' <- runIdentity $ runErrorT $ action
return g
should type check without issue. The problem is
doStuff :: (Map Int ()) -> Either String (Map Int ())
doStuff g = run (snd . head . Map.toList $ g) g where
run :: () -> Map Int () -> Either String (Map Int ())
run rhs g = do
let action = test rhs
rhs' <- runIdentity $ runErrorT $ action
return g
the reason for this is that you seem to have MonoLocalBinds or the Monomorphism Restriction enabled which prevents generalizations of the binding to action
unless the type is known.