单子提升M和函子fmap是否必须相等?

时间:2018-10-27 12:54:30

标签: haskell category-theory

(注意:我使用Haskell术语来表述这个问题;欢迎使用相同的术语和/或范畴论的数学语言来回答,包括适当的数学定义和公理,其中我涉及函子和莫纳德定律。)

众所周知,每个monad也是函子,函子的fmap等同于monad的liftM。这是有道理的,并且当然适用于所有常见/合理的monad实例。

我的问题是fmapliftM的等价性是否可以由函子和单子定律证明。如果是这样,很高兴看到如何做,如果不是,那么很高兴看到一个反例。

为澄清起见,我知道的函子和单子定律如下:

  • fmap idid
  • fmap f . fmap gfmap (f . g)
  • return x >>= ff x
  • x >>= returnx
  • (x >>= f) >>= gx >>= (\x -> f x >>= g)

在这些定律中,我没有看到任何将函子功能(fmap)与单子功能(return>>=)相关的内容,因此我很难看到如何从中得出fmapliftM(定义为liftM f x = x >>= (return . f))的等价关系。也许对此有一个论点,不足以让我发现吗?或者也许我错过了一些法律?

2 个答案:

答案 0 :(得分:9)

您错过的是参数定律,也称为自由定理。参数化的后果之一是所有多态函数都是自然变换。自然表示任何形式的多态函数

t :: F a -> G a

其中FG是仿函数,并与fmap通勤:

t . fmap f = fmap f . t

如果我们可以制作涉及liftM且具有自然变换形式的东西,那么我们将有一个与liftMfmap相关的方程式。 liftM本身不会产生自然转换:

liftM :: (a -> b) -> m a -> m b
              --       ^______^
              -- these need to be the same

但这是个主意,因为(a ->)是函子:

as :: m a
flip liftM as :: (a -> b) -> m b
              --  F    b  -> G b

让我们尝试在flip liftM m上使用参数性:

flip liftM m . fmap f = fmap f . flip liftM m

前一个fmap(a ->)函子上,其中fmap = (.),所以

flip liftM m . (.) f = fmap f . flip liftM m

Eta扩展

(flip liftM m . (.) f) g = (fmap f . flip liftM m) g
flip liftM m (f . g)     = fmap f (flip liftM m g)
liftM (f . g) m          = fmap f (liftM g m)

这是有希望的。以g = id

liftM (f . id) m = fmap f (liftM id m)
liftM f m        = fmap f (liftM id m)

显示liftM id = id就足够了。可能来自其定义:

liftM id m
   = m >>= return . id
   = m >>= return
   = m

是的! Qed。

答案 1 :(得分:6)

对于本练习,我发现使用public static void setDiet (Dinosaur dino, String TyranDiet) { dino.diet = TyranDiet; } public static void setHP (Dinosaur dino, int TyranHP) { dino.HP = TyranHP; } public static void setDamage (Dinosaur dino, int TyranDamage) { dino.damage = TyranDamage; } 比使用join更容易。可以通过>>=return来等效地定义一个monad,

join

实际上,1) join . join = join . fmap join 2) join . return = join . fmap return = id join是可互定义的:

>>=

您提到的法律与上述法律相对应(我不会证明这一点)。

然后,我们有:

x >>= f = join (fmap f x)
join x = x >>= id