3

モナドは適用可能なファンクターの拡張であると人々は言いますが、私にはわかりません。適用可能なファンクターの例を見てみましょう。(<*>) :: f(a->b) -> f a -> f b

[(+3)] <*> [2,3,4]

これで、モナドと同じことができると思います。つまり、コンテキストに関数が含まれているコンテキストと、コンテキストを取得するための別のコンテキストの2つのパラメーターを適用できるということです。しかし、モナドの場合、私はできません。必要なのは、次のような醜い関数を書くことだけです。

[2,3,4] >>= (\x->[x+3])

[(+3)]はい、もちろん、それはと同等であると言うことができます[\x->(x+3)]。しかし、少なくとも、この関数はコンテキスト内にあります。

最後に、ここでは同等性や拡張性はわかりません。モナドは別のスタイルであり、別の話で役立ちます。

私の無知でごめんなさい。

4

3 に答える 3

12

Tがのインスタンスである場合、次のようなMonadインスタンスにすることができます。Applicative

instance Functor T where
    fmap = liftM

instance Applicative T where
    pure = return
    (<*>) = ap

liftMと定義されている

liftM   :: (Monad m) => (a1 -> r) -> m a1 -> m r
liftM f m1              = do { x1 <- m1; return (f x1) }

apと定義されている

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) }

つまり、「モナドは適用可能なファンクターの拡張である」という意味で、どのモナドも適用可能なファンクターにすることができます。実際、クラスMonadがクラスから派生していないことは、標準ライブラリのバグと広く(普遍的にではなく)考えられていますApplicative

于 2012-11-23T17:56:31.140 に答える
9
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]

ここで、変数faの定義の最後の行の存在が、 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が呼び出す、を持っています。両方とも持っているか、両方ともファンクターであるためです。)NothinggetLineqgetLine>*>returnpure(<$>)fmap

checkFirstApplicativeで書くのに最も近いのは

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に似ていますが、存在する値に基づいて実行していることを完全に変更する機能を備えています。

于 2012-11-23T18:57:28.477 に答える
6

Haskellのモナドは、Applicative plus join、つまりモナドを「フラット化」する関数join :: m (m a) -> m aです。

「アプリケーションアプリケーション」の<*>タイプはf (a -> b) -> f a -> f b;です。同じファンクターに含めるタイプを選択した場合b、つまりb :: f c、タイプシグネチャはに特化してい<*> :: f (a -> f c) -> f a -> f (f c)ます。モナディック構造がない場合は、ここで完了です。ただし、モナドjoin関数を使用すると、結果をフラット化して、以前と同じモナドで(二重にスタックされたモナドの代わりに)何かを取得できます。

于 2012-11-23T22:58:53.320 に答える