从a gentle introduction to Haskell开始,有以下monad法律。任何人都可以直观地解释它们的含义吗?
return a >>= k = k a
m >>= return = m
xs >>= return . f = fmap f xs
m >>= (\x -> k x >>= h) = (m >>= k) >>= h
以下是我的尝试解释:
我们希望return函数包装a
,以便它的monadic性质是微不足道的。当我们将它绑定到一个函数时,没有monadic效果,它应该只将a
传递给函数。
m
的展开输出传递给重新包装的return
。 monadic性质保持不变。所以它和原来的monad一样。
将展开的值传递给f
然后重新包装。 monadic性质保持不变。这是我们将正常函数转换为monadic函数时所期望的行为。
我对这部法律没有解释。这确实说monad必须“几乎是联想的”。
答案 0 :(得分:45)
你的描述看起来很不错。一般来说,人们会说三个monad定律,你有1,2和4法律。你的第三定律略有不同,我稍后会谈到它。
对于三个monad定律,我发现直接理解使用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)相关性 - monadic组合是联想的(我喜欢KennyTM对此的回答)两个身份法基本上说同样的事情,但它们都是必要的,因为return
应该在绑定操作符的两边都有身份行为。
现在是第三定律。这个定律基本上说Functor实例和你的Monad实例在将一个函数提升到monad中时的行为方式相同,并且没有任何monadic。如果我没有弄错的话,那就是当monad遵守其他三个法律并且Functor实例遵守仿函数法则时,这个陈述将永远是真的。
其中很多来自Haskell Wiki。 Typeclassopedia也是一个很好的参考。
答案 1 :(得分:21)
与其他答案没有分歧,但可能有助于将monad法律视为实际描述两个属性集。正如约翰所说,你提到的第三条法则略有不同,但是其他的如何分开:
正如在约翰的回答中所说,monad的Kleisli箭头是类型为a -> m b
的函数。将return
视为id
,(<=<)
视为(.)
,monad法则是这些翻译:
id . f
相当于f
f . id
相当于f
(f . g) . h
相当于f . (g . h)
在大多数情况下,您可以将额外的monadic结构视为与monadic值相关的一系列额外行为;例如Maybe
为Nothing
“放弃”,Just
为“{继续”。结合两个monadic动作然后基本上连接他们所持有的行为序列。
从这个意义上说,return
又是一个身份 - 空行为,类似于一个空行为列表 - 而(>=>)
是串联。因此,monad法则是这些的翻译:
[] ++ xs
相当于xs
xs ++ []
相当于xs
(xs ++ ys) ++ zs
相当于xs ++ (ys ++ zs)
这三个定律描述了一种荒谬的共同模式,但不幸的是,Haskell无法完全表达这种模式。如果你感兴趣,Control.Category
给出了“看起来像函数组合的东西”的概括,而Data.Monoid
概括了后一种情况,其中没有涉及类型参数。
答案 2 :(得分:12)
就do
表示法而言,规则4意味着我们可以添加一个额外的do
块来对一系列monadic操作进行分组。
do do
y <- do
x <- m x <- m
y <- k x <=> k x
h y h y
这允许返回monadic值的函数正常工作。
答案 3 :(得分:4)
前三条法律规定“回归”只包装一个价值而不做任何其他事情。因此,您可以在不改变语义的情况下消除“返回”调用。
最后的法则是绑定的相关性。这意味着你采取了类似的东西:
do
x <- foo
bar x
z <- baz
并将其转换为
do
do
x <- foo
bar x
z <- baz
没有改变含义。当然你不会这样做,但是你可能想把内部的“do”子句放在“if”语句中,并且当“if”为真时希望它的含义相同。
有时monad并不完全遵循这些定律,特别是当出现某种底值时。只要记录在案并且“在道德上是正确的”(即非最低值遵循法律,或者以其他方式认为结果相同),那就没关系。