Monad
key way is to look inside ma
type and see a
; but the restriction of the Monad
key is that for monads there should be “unrecoverable” possible, that is, operations of the Monad
type should not be sufficient to write a function of the Monad m => ma -> a
type Monad m => ma -> a
. (>>=) :: Monad m => ma -> (a -> mb) -> mb
gives you exactly this ability.
But there is more than one way to achieve this. The Monad
class can be defined as follows:
class Functor f where fmap :: (a -> b) -> fa -> fb class Functor f => Monad m where return :: a -> ma join :: m (ma) -> ma
You ask why we cannot have the function Monad m => ma -> (ma -> mb) -> mb
. Well, given f :: a -> b
, fmap f :: ma -> mb
is basically that. But fmap
alone does not give you the opportunity to "look inside" Monad m => ma
, but cannot escape from it. However, join
and fmap
together give you this ability. (>>=)
can be written in general terms with fmap
and join
:
(>>=) :: Monad m => ma -> (a -> mb) -> mb ma >>= f = join (fmap f ma)
This is actually a common trick for defining an instance of Monad
when you have trouble defining for (>>=)
-write join
for your potential monad, and then use the generic definition (>>=)
.
Well, that answers the question, "should it be what it is," part of the no question. But why is it so?
I cannot speak for Haskell designers, but I like to think of it this way: in Haskell's monastic programming, the main building blocks are these actions:
getLine :: IO String putStrLn :: String -> IO ()
In general, these basic building blocks are of types that look like Monad m => ma
, Monad m => a -> mb
, Monad m => a -> b -> mc
, ..., Monad m => a -> b -> ... -> mz
. People informally call these actions. Monad m => ma
- action without an argument, Monad m => a -> mb
- action with one argument, etc.
Well, (>>=) :: Monad m => ma -> (a -> mb) -> mb
is basically the simplest function that "binds" two actions. getLine >>= putStrLn
is the action that getLine
first executes and then putStrLn
, passing it the result obtained from getLine
. If you had fmap
and join
, and not >>=
, you would have to write this:
join (fmap putStrLn getLine)
More generally (>>=)
embodies a concept very similar to the "pipeline" of actions, and as such is a more useful operator for using monads as a kind of programming language.
The final thing: make sure you know the Control.Monad
module. Although return
and (>>=)
are the main functions for monads, there are endless other higher-level functions that you can define using these two, and this module collects several dozen of the most common. Your code should not be transferred to a straitjacket on (>>=)
; it is an important building block that is useful both on its own and as a component for large building blocks.