import Control.Applicative
もう一度定義する関係が明確になると思います<*>
が、モナドを使用します。
(>*>) :: 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
ますa
。
類似点
Applicativeでは、次のことができます
getNonEmptyStringA :: IO String
getNonEmptyStringA = (:) <$> getChar <*> getLine
これをモナド関数に変換できます
getNonEmptyStringM' = (:) `fmap` getChar >*> getLine
またはより一般的には、
getNonEmptyStringM :: IO String
getNonEmptyStringM = do
c <- getChar
xs <- getLine
return (c:xs)
違い
モナドではあなたができる
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キーを押したりする機会を与えずにすぐn
に戻りましたが、最初から実行すると実行が続行されます。値の強さで行われることを変更するこの機能は、MonadとApplicativeの主な違いですが、MonadがApplicativeが行うすべてのことを行うことがオペレーターでわかります。(どちらも、Applicativeが呼び出す、を持っています。両方とも持っているか、両方ともファンクターであるためです。)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
との違いはわかりません。)don'tCheckFirst
概要
モナドはApplicativeに似ていますが、存在する値に基づいて実行していることを完全に変更する機能を備えています。