簡體   English   中英

應用函子和monad之間的等價性

[英]the equivalence between applicative functor and monad

人們說monad是應用函子的延伸,但我沒有看到。 讓我們舉一個applicative functor的例子: (<*>) :: f(a->b) -> fa -> fb

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

現在,我也期望我可以做與monad相同的事情,這意味着我可以應用2個參數:上下文包含一個函數,另一個上下文來獲取上下文。 但是對於monad,我不能。 我只需要寫一個像這樣丑陋的函數:

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

是的,當然,你可以說[(+3)]相當於[\\x->(x+3)] 但至少,這個功能是在上下文中。

最后,我沒有在這里看到等價或擴展。 Monad是另一種風格,在另一個故事中很有用。

對不起我的無知。

如果TMonad一個實例,那么你可以使它成為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是應用函子的擴展”,因為任何monad都可以被制作成一個applicative functor。 實際上,廣泛(並非普遍)認為標准庫中的一個錯誤是Monad類不是從Applicative類派生的。

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]

現在,變量fa的存在以及>*>定義中的最后一行是Monad和Applicative之間的關鍵區別 在Applicative中,你只能在最后return一些東西,而在Monad中,你可以用fa做任何你喜歡的事情。

相似

在Applicative中,你可以這樣做

getNonEmptyStringA :: IO String
getNonEmptyStringA = (:) <$> getChar <*> getLine

我們可以將其轉換為Monad函數

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改變了我鍵入n之后發生的事情 - 它直接返回Nothing而沒有給我機會為getLine鍵入內容或按Enter鍵,而如果我從q開始它繼續運行getLine 這種改變在的強度上完成的能力是Monad和Applicative之間的關鍵區別,但是你可以看到>*>運算符,Monad完成了Applicative所做的一切。 (它們都有return ,Applicative稱為pure ,並且它們都有(<$>)fmap因為它們都是fmap 。)

你最接近在Applicative寫的checkFirst

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"

(注意:由於don'tCheckFirst中的Windows ghc錯誤,你無法在windows中的ghci中區分checkFirstdon'tCheckFirst之間的區別。)

摘要

Monad就像是Applicative,但有能力根據有什么價值完全改變你正在做的事情。

Haskell中的monad是Applicative plus join ,即“展平”monad的函數, join :: m (ma) -> ma

“Applicative application” <*>類型為f (a -> b) -> fa -> fb ; 如果您現在選擇類型b在同一個Functor中,即b :: fc ,則類型簽名專門用於<*> :: f (a -> fc) -> fa -> f (fc) 當你沒有monadic結構時,你就完成了; 但是,使用monadic join函數,你可以展平結果,獲得與之前相同的monad中的某些東西(而不是雙堆疊monad)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM