2012-02-01 26 views

回答

26

那么,fmap只是(a -> b) -> f a -> f b,即我们想要用一个纯函数来转换monadic动作的结果。这很简单,用做记号写:

fmap f m = do 
    a <- m 
    return (f a) 

,或者写着 “原始”:

fmap f m = m >>= \a -> return (f a) 

这可作为Control.Monad.liftM

pure :: a -> f a当然是return(<*>) :: f (a -> b) -> f a -> f b有点棘手。我们有一个动作返回一个函数,一个动作返回它的参数,我们想要一个返回结果的动作。在再做记号:

mf <*> mx = do 
    f <- mf 
    x <- mx 
    return (f x) 

或者脱:

mf <*> mx = 
    mf >>= \f -> 
    mx >>= \x -> 
    return (f x) 

田田!这可作为Control.Monad.ap,所以我们可以给的FunctorApplicative一个完整的实例任何单子M如下:

instance Functor M where 
    fmap = liftM 

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

理想情况下,我们就可以直接在Monad指定这些实现,以减轻负担为每个monad定义单独的实例,例如this proposal。如果发生这种情况,将Applicative设为Monad的超类并不存在真正的障碍,因为它可以确保它不会破坏任何现有的代码。另一方面,这意味着为给定的Monad定义FunctorApplicative实例所涉及的样板很少,所以很容易成为“好公民”(并且应该为任何monad定义这样的实例)。

+5

这个答案缺少一个重要的部分:证明如果一个给定的'Monad'实例'm'确实满足Monad定律,那么你提供给'fmap','pure'和[(<*>)'的单子定义'服从法师和适用法律。 Haskell强制执行的是类型检查。 – 2012-02-03 02:04:22

10

fmap = liftM(<*>) = ap。以下是指向liftMap的源代码的链接。我认为你知道如何去掉符号。

相关问题