data M a = M a deriving (Show)
unitM a = M a
bindM (M a) f = f a
joinM :: M (M a) -> M a
joinM m = m `bindM` id
joinM' :: M a -> a
joinM' m = m `bindM` id
Note that joinM (M 0)
will fail to type check, whereas joinM' (M 0)
will be fine.
My question: why is joinM
defined as M (M a) -> M a
but not as M a -> a
?
From my understanding,
unitM
puts the value a
into the monad M a
joinM
gets the value a
from the monad M a
So joinM
should really work on any monad, i.e., not necessarily nested ones such as M (M a)
, right?
The point of monads is that you can't get a value out of them. If join
had type m a -> a
then the IO
monad would be perfectly useless, since you could just extract the values freely. The point of monads is that you can chain computations together (>>=
can be defined in terms of join
, provided you have return
and fmap
) and put values into a monadic context, but you can't (in general) get them out.
In your specific case, you've defined what is essentially the identity monad. In that case, it's easy to extract the value; you just strip away the layer of M
and move on with your life. But that's not true for general monads, so we restrict the type of join
so that more things can be monads.
Your bindM
is not of the correct type, by the way. The general type of >>=
is
(>>=) :: Monad m => m a -> (a -> m b) -> m b
Your function has type
bindM :: M a -> (a -> b) -> b
Notice that your type is more general. Hence, again, in your specific case, you can get away with being looser on the requirements of joinM
, whereas specific monads cannot. Try giving bindM
an explicit type signature of M a -> (a -> M b) -> M b
and then see if both of your join functions still typecheck.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments