15

众所周知,Monad 在理论上是函子的子集,特别是应用函子,尽管 Haskell 的类型系统中没有指出。

知道这一点,给定一个 monad 并基于returnand bind,如何:

  • 导出fmap,
  • 导出<*>?
4

2 回答 2

26

好吧,fmap就是(a -> b) -> f a -> f b,即我们想用一个纯函数来转换一元动作的结果。用 do 表示法很容易写:

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有点棘手。我们有一个动作返回一个函数,一个动作返回它的参数,我们想要一个动作返回它的结果。再次使用 do 表示法:

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

或者,脱糖:

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

多田!这可用作,因此我们可以为任何 monadControl.Monad.ap提供一个完整的实例,Functor如下所示:ApplicativeM

instance Functor M where
  fmap = liftM

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

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

于 2012-02-01T15:22:13.070 回答
10

fmap = liftM(<*>) = ap。以下是liftMap源代码的链接。我想你知道如何对 do 符号进行脱糖。

于 2012-02-01T15:17:50.503 回答