问题
People say monads are an extension of applicative functors, but I don't see that. Let's take an example of applicative functor: (<*>) :: f(a->b) -> f a -> f b
[(+3)] <*> [2,3,4]
Now, I also expect I can do the same thing as monad, it means I can apply 2 parameters: a context contains a function, and another context to get a context. But for monad, I can't. All I need is to write an ugly function like this:
[2,3,4] >>= (\x->[x+3])
Yes, of course, you can say that [(+3)] is equivalent to [\x->(x+3)]. But at least, this function is in context.
Finally, I don't see the equivalence or extension here. Monad is a different style and useful in another story.
Sorry for my ignorance.
回答1:
If T is an instance of Monad, then you can make it an instance of Applicative like this:
instance Functor T where
fmap = liftM
instance Applicative T where
pure = return
(<*>) = ap
liftM is defined as
liftM :: (Monad m) => (a1 -> r) -> m a1 -> m r
liftM f m1 = do { x1 <- m1; return (f x1) }
ap is defined as
ap :: (Monad m) => m (a -> b) -> m a -> m b
ap = liftM2 id
liftM2 :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r
liftM2 f m1 m2 = do { x1 <- m1; x2 <- m2; return (f x1 x2) }
So, "monads are an extension of applicative functors" in the sense that any monad can be made into an applicative functor. Indeed, it is widely (not universally) considered a bug in the standard library that class Monad does not derive from class Applicative.
回答2:
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.
回答3:
A monad in Haskell is an Applicative plus join, i.e. a function to "flatten" the monad, join :: m (m a) -> m a.
The "Applicative application" <*> has type f (a -> b) -> f a -> f b; if you now choose the type b to be in the same Functor, i.e. b :: f c, the type signature specializes to <*> :: f (a -> f c) -> f a -> f (f c). When you don't have a monadic structure, you're done here; however, using the monadic join function, you can flatten the result, getting something in the same monad as before (instead of a double stacked monad).
来源:https://stackoverflow.com/questions/13533769/the-equivalence-between-applicative-functor-and-monad