Monads在理论上被称为函子的一个子集,特别适用于函子,尽管它在Haskell的类型系统中没有被指出。如何显示monad是一个仿函数和一个应用函子?
知道了,给定一个单子,并立足于return
和bind
,如何:
- 获得
fmap
, - 获得
<*>
?
Monads在理论上被称为函子的一个子集,特别适用于函子,尽管它在Haskell的类型系统中没有被指出。如何显示monad是一个仿函数和一个应用函子?
知道了,给定一个单子,并立足于return
和bind
,如何:
fmap
,<*>
?那么,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
,所以我们可以给的Functor
和Applicative
一个完整的实例任何单子M
如下:
instance Functor M where
fmap = liftM
instance Applicative M where
pure = return
(<*>) = ap
理想情况下,我们就可以直接在Monad
指定这些实现,以减轻负担为每个monad定义单独的实例,例如this proposal。如果发生这种情况,将Applicative
设为Monad
的超类并不存在真正的障碍,因为它可以确保它不会破坏任何现有的代码。另一方面,这意味着为给定的Monad
定义Functor
和Applicative
实例所涉及的样板很少,所以很容易成为“好公民”(并且应该为任何monad定义这样的实例)。
这个答案缺少一个重要的部分:证明如果一个给定的'Monad'实例'm'确实满足Monad定律,那么你提供给'fmap','pure'和[(<*>)'的单子定义'服从法师和适用法律。 Haskell强制执行的是类型检查。 – 2012-02-03 02:04:22