monad法律传统上用>>=
和pure
来描述:
pure a >>= k = k a
m >>= pure = m
m >>= (\x -> k x >>= h) = (m >>= k) >>= h
但是,monad也可以用join
而不是>>=
来定义。我想根据join
提出monad法律的表述。
使用x >>= f = join (fmap f x)
,可以轻松重写现有的monad法则以消除>>=
。在适用法律的帮助下,略微简化了结果,前两条法律得到了非常愉快的表达:
join . pure = id
join . fmap pure = id
对这些法则的直觉也很容易,因为很明显,当与pure
结合使用join
时,引入额外的“层”应该是无操作。然而,第三定律并不是那么好。最终看起来像这样:
join (fmap (\x -> join (fmap h (k x))) m)
= join (fmap h (join (fmap k m)))
这并没有使用适用的法律令人愉快地减少,而且如果不盯着它看一段时间就很难理解。它当然不具备相同的直觉。
对join
方面的monad法则是否有更容易理解的等效替代公式?或者,有没有办法简化上述法律,或者让它更容易理解? >>=
的版本已经不如使用Kleisli合成的版本好,但join
的版本几乎不可读。
答案 0 :(得分:18)
直接从Wikipedia:
被盗(自然变换η: 1 -> T
为pure
;自然变换µ: T^2 -> T
为join
)
µ . Tµ = µ . µT
在Haskell:
join . fmap join = join . join
英文版:如果你从mmma :: Monad m => m (m (m a))
开始使用三层monad,那么先将内层压平,然后将其展平为外层,或者先将外层展平为内层,然后将其展平,则无关紧要。这与您列为第三(关联性)的法律相同。
µ . Tη = µ . ηT = 1
在Haskell:
join . fmap pure = join . pure = id
英文:如果你从一层monad开始为ma :: Monad m => m a
,那么你在它内部创建一个新图层然后展平它,或者如果你在它之外创建一个新图层然后再无关紧要压扁它,两者都是无所事事。这项法律是你的前两个法律的组合。