(注意:我使用Haskell术语来表述这个问题;欢迎使用相同的术语和/或范畴论的数学语言来回答,包括适当的数学定义和公理,其中我涉及函子和莫纳德定律。)
众所周知,每个monad也是函子,函子的fmap
等同于monad的liftM
。这是有道理的,并且当然适用于所有常见/合理的monad实例。
我的问题是fmap
和liftM
的等价性是否可以由函子和单子定律证明。如果是这样,很高兴看到如何做,如果不是,那么很高兴看到一个反例。
为澄清起见,我知道的函子和单子定律如下:
fmap id
≡id
fmap f . fmap g
≡fmap (f . g)
return x >>= f
≡f x
x >>= return
≡x
(x >>= f) >>= g
≡x >>= (\x -> f x >>= g)
在这些定律中,我没有看到任何将函子功能(fmap
)与单子功能(return
和>>=
)相关的内容,因此我很难看到如何从中得出fmap
和liftM
(定义为liftM f x = x >>= (return . f)
)的等价关系。也许对此有一个论点,不足以让我发现吗?或者也许我错过了一些法律?
答案 0 :(得分:9)
您错过的是参数定律,也称为自由定理。参数化的后果之一是所有多态函数都是自然变换。自然表示任何形式的多态函数
t :: F a -> G a
其中F
和G
是仿函数,并与fmap
通勤:
t . fmap f = fmap f . t
如果我们可以制作涉及liftM
且具有自然变换形式的东西,那么我们将有一个与liftM
和fmap
相关的方程式。 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