The explanation is:
- Your
return
is (perhaps unexpectedly) of a different monad than your =<<
.
- The monad it uses is the reader monad
(->) r
.
The compiler tries to unify the result of return :: c -> m' c
with the first argument of (a -> m b) -> m a -> m b
, so to unify m' c
with a -> m b
. The only possibility is that m'
is the reader monad (->) r
for some r
. Next, it tries to unify (->) r c
with (converted to the prefix notation) (->) a (m b)
, which is solved by setting r
to a
and c
to m b
. So, after unification, the compiler gets the most general possible type
return :: (m b) -> ((->) a (m b))
or in the usual infix notation
return :: (m b) -> (a -> m b)
See also:
Edit: To define a monad, we need a (partially applied) type of kind * -> *
. These are almost always partially applied data constructors, but this particular case, we view ->
as a type operator that takes 2 type arguments and creates a new type (the function type). So for any given type r
, the partially applied expression (->) r
is a type of kind * -> *
. As it turns out, there is a straightforward way how to describe monad operations on it. See Control.Reader monad and also this article that explains it. The monad operations for Reader
are implemented exactly the same way as for (->)
, the only difference is that Reader
wraps the operations into a distinct data type.