繁体   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