haskell - 单子(monad) liftM 和仿函数 fmap 必须相等吗?

标签 haskell category-theory

(注意:我使用 Haskell 术语来表达问题;欢迎使用相同的术语和/或范畴论的数学语言来回答,包括我谈到仿函数和单子(monad)定律时的正确数学定义和公理。)

众所周知,每个 monad 也是一个仿函数,仿函数的 fmap 相当于 monad 的 liftM。这是有道理的,当然适用于所有常见/合理的 monad 实例。

我的问题是 fmapliftM 的等价性是否可以证明遵循仿函数和单子(monad)定律。如果是这样,那么很高兴看到如何实现,如果没有,那么很高兴看到反例。

澄清一下,我所知道的仿函数和单子(monad)定律如下:

  • fmap id == id
  • fmap f 。 fmap g == fmap (f . g)
  • 返回 x >>= ff x
  • x >>= returnx
  • (x >>= f) >>= gx >>= (\x -> f x >>= g)

我在这些法律中没有看到任何将仿函数功能(fmap)与 monad 功能(return>>=),所以我发现很难看出 fmapliftM 的等价性(定义为 liftM f x = x >>= (return . f) ) 可以从它们中派生出来。也许有一个论点对我来说还不够简单?或者也许我遗漏了一些法律?

最佳答案

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

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

埃塔展开

(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。

关于haskell - 单子(monad) liftM 和仿函数 fmap 必须相等吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53022087/

相关文章:

generics - Clojure 相当于 Haskell 的 "Scrap Your Boilerplate"(SYB)

haskell - 哪些编程语言有类似 Haskell 的 `newtype`

haskell - 不能从这个表达式导出(显示)

haskell - 使用 Haskell 的 zip-conduit 从 zip 存档中的文件中读取行

haskell - Do 符号和 Monad 组合

haskell - 我如何使用递归方案来表达 Haskell 中的概率分布

Scala - 创建类型集合的惯用方式

haskell - 为什么 ArrowApply 在证明与 Monads 等价时是唯一的选择?

haskell - 使用 scanl Haskell 计算斐波那契数的大 0

haskell - Haskell中扩展类型类的含义是什么?