繁体   English   中英

摩纳德法律解释

[英]Explanation of Monad laws

对Haskell的简要介绍开始 ,有以下monad定律。 任何人都可以凭直觉解释它们的意思吗?

return a >>= k             = k a
m >>= return               = m
xs >>= return . f          = fmap f xs
m >>= (\x -> k x >>= h)    = (m >>= k) >>= h

这是我尝试的解释:

  1. 我们希望return函数可以包装a以便其单调性很简单。 当我们将其绑定到函数时,没有单调效果,它应该将a传递给函数。

  2. 传递m的未包装输出以return重新包装它的return 单子性保持不变。 因此它与原始monad相同。

  3. 未包装的值传递给f然后重新包装。 单子性保持不变。 这是将正常函数转换为单子函数时预期的行为。

  4. 我对此法律没有任何解释。 这确实表明单子必须“几乎是关联的”。

您的描述似乎不错。 通常,人们会说三个monad定律,分别为1、2和4。您的第三定律稍有不同,我将在后面进行介绍。

对于这三个单子法则,我发现更容易直观地了解使用Kleisli组合法重写它们时的含义:

-- defined in Control.Monad
(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c
mf >=> n = \x -> mf x >>= n

现在法律可以写成:

1) return >=> mf = mf                  -- left identity
2) mf >=> return = mf                  -- right identity
4) (f >=> g) >=> h = f >=> (g >=> h)   -- associativity

1)左身定律-返回值不会更改值,并且在monad中不会执行任何操作。

2)权利识别法-返回值不会更改值,并且在monad中不会执行任何操作。

4)联想-单子组合是联想的(我喜欢KennyTM的答案)

两种身份定律基本上说的是同一件事,但是它们都是必需的,因为return应该在绑定运算符的两侧都具有身份行为。

现在为第三定律。 该定律从本质上说,将函数提升到monad时,Functor实例和您的Monad实例的行为均相同,并且monadic也不起作用。 如果我没有记错的话,那么当一个monad遵守其他三个定律而Functor实例遵守该函子定律时,这种说法将永远是正确的。

其中很多来自Haskell Wiki Typeclassopedia也是一个很好的参考。

与其他的答案没有分歧,但它可能会不由自主地想起的单子法律的实际描述两套属性。 如John所说,您提到的第三条法则略有不同,但是以下是其他法则可以分开的方法:

绑定到monad的功能与常规功能一样组成。

就像约翰的回答一样,单子的Kleisli箭头是类型为a- a -> mb的函数。 return视为id并将(<=<)视为(.) ,monad定律就是这些的翻译:

  1. id . f id . f等于f
  2. f . id f . id等于f
  3. (f . g) . h (f . g) . h等于f . (g . h) f . (g . h)

单调效果的序列附加类似列表。

在大多数情况下,您可以将额外的单子结构视为与单子值相关的一系列额外行为。 例如, Maybe是“放弃”了Nothing ,并“继续下去”为Just 然后,将两个单子动作组合起来就可以将它们所持有的一系列行为串联起来。

从这个意义上讲, return再次是一个标识-空操作,类似于一个空的行为列表- (>=>)是串联。 因此,单子法则是这些的翻译:

  1. [] ++ xs等效于xs
  2. xs ++ []等同于xs
  3. (xs ++ ys) ++ zs等效于xs ++ (ys ++ zs)

这三个定律描述了一个荒谬的通用模式,不幸的是,Haskell无法完全概括性地表达这种模式。 如果您有兴趣, Control.Category可以概括为“看起来像函数组合的事物”,而Data.Monoid概括为后者,其中不涉及任何类型参数。

do表示法方面,规则4表示我们可以添加一个额外的do块来对一系列monadic操作进行分组。

    do                          do
                                  y <- do
      x <- m                             x <- m
      y <- k x          <=>              k x
      h y                         h y

这使返回单值的函数正常工作。

前三个定律说“返回”只包装一个值,而没有其他作用。 因此,您可以在不更改语义的情况下消除“返回”调用。

最后一条定律是绑定的关联性。 这意味着您需要执行以下操作:

do
   x <- foo
   bar x
   z <- baz

然后变成

do
   do
      x <- foo
      bar x
   z <- baz

不改变含义。 当然,您不会完全做到这一点,但是您可能希望将内部的“ do”子句放在“ if”语句中,并希望在“ if”为真时其含义相同。

有时候,单子并不完全遵循这些定律,尤其是在发生某种最低值时。 只要记录在案,并且“在道德上是正确的”(即遵循非底值的法律,或者在其他方面认为结果等效),也可以。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM