import Control.Applicative
I think it clarifies the relationship to define <*>
again, but using a Monad:
(>*>) :: Monad m => m (a -> b) -> m a -> m b
mf >*> ma = do
f <- mf
a <- ma
return (f a)
Giving the same results as <*>
:
*Main> [(+3)] >*> [2,3,4]
[5,6,7]
*Main> [(+3)] <*> [2,3,4]
[5,6,7]
or even
*Main> [(+3),(*10)] <*> [2,3,4]
[5,6,7,20,30,40]
*Main> [(+3),(*10)] >*> [2,3,4]
[5,6,7,20,30,40]
Now the presence of the variables f
and a
and the last line in the definition of >*>
is the key difference between Monad and Applicative.
In Applicative, you can only return
something at the end, whereas in a Monad, you can do whatever you like with f
and a
.
Similarities
In Applicative, you could do
getNonEmptyStringA :: IO String
getNonEmptyStringA = (:) <$> getChar <*> getLine
Which we could translate into Monad functions as
getNonEmptyStringM' = (:) `fmap` getChar >*> getLine
or more typically,
getNonEmptyStringM :: IO String
getNonEmptyStringM = do
c <- getChar
xs <- getLine
return (c:xs)
Difference
In Monad you could do
checkFirst :: IO (Maybe String)
checkFirst = do
c <- getChar
if c == 'n' then return Nothing
else fmap Just getLine
For example,
Main> checkFirst >>= print
qwerty
Just "werty"
Main> checkFirst >>= print
nNothing
Notice that checkFirst
changed what happened after I typed the n
- it returned Nothing
straight away without giving me a chance to type something for getLine
or to press enter, whereas if I start with q
it carries on to run getLine
. This ability to change what gets done on the strength of the values is the key difference between Monad and Applicative, but you can see with the >*>
operator that Monad does everything Applicative does. (They both have return
, which Applicative calls pure
, and they both have (<$>)
or fmap
because they're both Functors.)
The closest you can get to writing checkFirst
in Applicative is
don'tCheckFirst :: IO (Maybe String)
don'tCheckFirst = check <$> getChar <*> getLine where
check c xs = if c == 'n' then Nothing
else Just (c:xs)
Which works like this:
Main> don'tCheckFirst >>= print
nI can keep typing because it has to do the getLine anyway
Nothing
Main> don'tCheckFirst >>= print
qwerty
Just "qwerty"
(Note: you can't tell the difference between checkFirst
and don'tCheckFirst
in ghci in windows, because of a Windows ghc bug in getChar.)
Summary
Monad is like Applicative but with the ability to completely change what you're doing based on what values there are.
pure = return
andmf <*> ma = mf >>= \f -> liftM f ma
.[2,3,4] >>= \ x -> replicate x x
really need the extra power of>>=
, because each value is used to choose the structure of the resulting list, not just the values inside it. The monad operations are strictly more powerful, but correspondingly, they're not as commonly available.