Monad在理论上被认为是仿函数的一个子集,特别是应用仿函数,尽管它没有在Haskell的类型系统中指出 .
知道这一点,给定一个monad并基于 return 和 bind ,如何:
return
bind
derive fmap ,
fmap
derive <*> ?
<*>
那么, fmap 只是 (a -> b) -> f a -> f b ,即我们想用变符号来改变monadic动作's result with a pure function. That' s易于编写:
(a -> b) -> f a -> f b
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 有点棘手 . 我们有一个返回函数的动作,以及一个返回其参数的动作,我们希望一个动作返回它的结果 . 在再次表示法:
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
mf <*> mx = do f <- mf x <- mx return (f x)
或者,desugared:
mf <*> mx = mf >>= \f -> mx >>= \x -> return (f x)
田田!这是Control.Monad.ap,因此我们可以为任何monad M 提供 Functor 和 Applicative 的完整实例,如下所示:
M
Functor
Applicative
instance Functor M where fmap = liftM instance Applicative M where pure = return (<*>) = ap
理想情况下,我们可以直接在 Monad 中指定这些实现,以减轻为每个monad定义单独实例的负担,例如使用this proposal . 如果发生这种情况,那么使 Applicative 成为 Monad 的超类将没有真正的障碍,因为它会破坏任何现有代码 . 另一方面,这意味着为给定 Monad 定义 Functor 和 Applicative 实例所涉及的样板文件是最小的,因此很容易成为"good citizen"(并且应该为任何monad定义此类实例) .
Monad
fmap = liftM 和 (<*>) = ap . 以下是liftM和ap源代码的链接 . 我认为你知道如何desugar做符号 .
fmap = liftM
(<*>) = ap
2 回答
那么,
fmap
只是(a -> b) -> f a -> f b
,即我们想用变符号来改变monadic动作's result with a pure function. That' s易于编写:或者,写成“原始”:
这可以作为Control.Monad.liftM获得 .
pure :: a -> f a
当然是return
.(<*>) :: f (a -> b) -> f a -> f b
有点棘手 . 我们有一个返回函数的动作,以及一个返回其参数的动作,我们希望一个动作返回它的结果 . 在再次表示法:或者,desugared:
田田!这是Control.Monad.ap,因此我们可以为任何monad
M
提供Functor
和Applicative
的完整实例,如下所示:理想情况下,我们可以直接在
Monad
中指定这些实现,以减轻为每个monad定义单独实例的负担,例如使用this proposal . 如果发生这种情况,那么使Applicative
成为Monad
的超类将没有真正的障碍,因为它会破坏任何现有代码 . 另一方面,这意味着为给定Monad
定义Functor
和Applicative
实例所涉及的样板文件是最小的,因此很容易成为"good citizen"(并且应该为任何monad定义此类实例) .fmap = liftM
和(<*>) = ap
. 以下是liftM和ap源代码的链接 . 我认为你知道如何desugar做符号 .