haskell - the type of join function

Lin
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?

Silvio Mayolo

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.

edited at
0

Comments

0 comments
Login to comment

Related