如何证明monad是一个仿函数和一个应用函子?

时间:2012-02-01 15:12:32

标签: haskell monads functor applicative

Monad在理论上被认为是仿函数的一个子集,特别是应用仿函数,尽管在Haskell的类型系统中没有指出它。

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

  • 派生fmap
  • 派生<*>

2 个答案:

答案 0 :(得分:26)

嗯,fmap只是(a -> b) -> f a -> f b,即我们想用纯函数转换monadic动作的结果。用表示法写起来很容易:

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

或写成“raw”:

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)

或者,desugared:

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

多田!这可以Control.Monad.ap获取,因此我们可以为任何monad Functor提供ApplicativeM的完整实例,如下所示:

instance Functor M where
  fmap = liftM

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

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

答案 1 :(得分:10)

fmap = liftM(<*>) = ap。以下是liftMap源代码的链接。我认为你知道如何使用desugar。