import Control.Applicative
我认为它澄清了<*>
再次定义的关系,但使用了 Monad:
(>*>) :: Monad m => m (a -> b) -> m a -> m b
mf >*> ma = do
f <- mf
a <- ma
return (f a)
给出与以下相同的结果<*>
:
*Main> [(+3)] >*> [2,3,4]
[5,6,7]
*Main> [(+3)] <*> [2,3,4]
[5,6,7]
甚至
*Main> [(+3),(*10)] <*> [2,3,4]
[5,6,7,20,30,40]
*Main> [(+3),(*10)] >*> [2,3,4]
[5,6,7,20,30,40]
现在,变量f
和a
定义中最后一行的存在是Monad 和 Applicative 之间>*>
的关键区别。在 Applicative 中,你只能return
在末尾做一些事情,而在 Monad 中,你可以用f
and做任何你喜欢的事情a
。
相似之处
在应用程序中,你可以做
getNonEmptyStringA :: IO String
getNonEmptyStringA = (:) <$> getChar <*> getLine
我们可以将其转换为 Monad 函数
getNonEmptyStringM' = (:) `fmap` getChar >*> getLine
或更典型地,
getNonEmptyStringM :: IO String
getNonEmptyStringM = do
c <- getChar
xs <- getLine
return (c:xs)
区别
在 Monad 你可以做
checkFirst :: IO (Maybe String)
checkFirst = do
c <- getChar
if c == 'n' then return Nothing
else fmap Just getLine
例如,
Main> checkFirst >>= print
qwerty
Just "werty"
Main> checkFirst >>= print
nNothing
请注意,在我输入- 它checkFirst
之后发生的事情发生了变化,它立即返回,而我没有机会输入或按 Enter 键,而如果我从它开始,它会继续运行。这种根据值的强度改变所做工作的能力是 Monad 和 Applicative 之间的主要区别,但是您可以通过运算符看到 Monad 完成了 Applicative 所做的一切。(它们都有,Applicative 调用它们,它们都有or因为它们都是 Functor。)n
Nothing
getLine
q
getLine
>*>
return
pure
(<$>)
fmap
checkFirst
您可以在 Applicative 中最接近写作的是
don'tCheckFirst :: IO (Maybe String)
don'tCheckFirst = check <$> getChar <*> getLine where
check c xs = if c == 'n' then Nothing
else Just (c:xs)
像这样工作:
Main> don'tCheckFirst >>= print
nI can keep typing because it has to do the getLine anyway
Nothing
Main> don'tCheckFirst >>= print
qwerty
Just "qwerty"
(注意:由于getChar 中的 Windows ghc 错误,您无法区分windows 中的 ghcicheckFirst
和in 。)don'tCheckFirst
概括
Monad 类似于 Applicative,但能够根据存在的值完全改变你正在做的事情。