2
votes

I try to work with the Reader Monad

m = Map.fromList [("a","b"), ("b","c"), ("c","d"), ("d","e")]
f x m = fromMaybe "default value" $ Map.lookup x m

lookup' x = f x m

Now I wanted to create a reader monad:

r = reader lookup'
-- Non type variable argument:
--   in the constraint MonadReader [Char] m
-- When checking the inferred type:
--   b :: forall (m :: * -> *). MonadReader [Char] m => m [Char]

The solution was to define the type:

r = reader lookup' :: Reader String String

Why does this solve the problem?

1
Import Control.Monad.Trans.Reader instead of Control.Monad.Reader. The latter exposes a more general interface which sometimes makes more concise code, but also sometimes causes ambiguity messages like the one you got. To find out more about this particular sort of stuff, read up on the difference between transformers and mtl.Alec

1 Answers

3
votes

The immediate problem is due to the monomorphism restriction. The hand-waving explanation for this case is that r = reader lookup' looks like you are defining some concrete r, so Haskell will try to infer a monomorphic type signature for it (one without type variables).

Since you imported reader :: MonadReader r m => (r -> a) -> m a, the Haskell infers that reader lookup' :: MonadReader [Char] m => m [Char]. Unfortunately, this is not monomorphic - Haskell doesn't know exactly what you want m to be. That is what the error message is saying: the type variable m is ambiguous.

Adding an explicit type annotation like reader lookup' :: Reader String String removes this problem; it is now possible to infer that m ~ Reader String.