以连接而不是绑定的方式表达的 Monad 法则?

Monad laws expressed in terms of join instead of bind?

Monad 法则传统上用 >>=pure 来描述:

pure a >>= k = k a
m >>= pure = m
m >>= (\x -> k x >>= h) = (m >>= k) >>= h

然而,monads 也可以用 join 而不是 >>= 来定义。我想根据 join.

提出 monad 法则的表述

使用x >>= f = join (fmap f x),很容易重写现有的单子法则来消除>>=。借助应用法则稍微简化一下结果,前两个法则表达得相当愉快:

join . pure = id
join . fmap pure = id

这些定律的直觉也很容易,因为很明显,在与 join 结合使用时,使用 pure 引入额外的“层”应该是空操作。然而,第三定律就没那么好了。它最终看起来像这样:

  join (fmap (\x -> join (fmap h (k x))) m)
= join (fmap h (join (fmap k m)))

这并没有令人愉快地减少应用法则的使用,而且如果不盯着它看一会儿就更难理解了。它当然没有同样简单的直觉。

是否有更容易理解的 join 单子法则的等效替代表述?或者,有没有什么办法可以简化上述法则,或者让它更容易理解? >>= 的版本已经不如 Kleisli 组合表达的好,但是 join 的版本几乎不可读。

直接从Wikipedia偷来的:

(自然变换η: 1 -> Tpure;自然变换µ: T^2 -> Tjoin)

µ . Tµ = µ . µT

在Haskell中:

join . fmap join = join . join

英文:如果你从三层monad开始,如mmma :: Monad m => m (m (m a)),先压平内层再压外层,还是先压压外层再压内层都无所谓。这与您列为第三条(结合律)的定律相同。

µ . Tη = µ . ηT = 1

在Haskell中:

join . fmap pure = join . pure = id

英文:如果你从一层 monad 开始,如 ma :: Monad m => m a,无论你在里面创建一个新层然后展平它,还是在它外面创建一个新层都没有关系然后压扁它,两者都和什么都不做一样。这个定律是你前两个的结合。

此外,join 是自然变换意味着

join . fmap (fmap f) = fmap f . join

因为参数化。