Monad法则解释
从Haskell的一个温和的介绍,有以下monad法律。 任何人都可以直观地解释他们的意思吗?
return a >>= k = k a
m >>= return = m
xs >>= return . f = fmap f xs
m >>= (x -> k x >>= h) = (m >>= k) >>= h
这是我的尝试解释:
我们期望返回函数包装a
以便它的monadic本质是微不足道的。 当我们将它绑定到函数时,没有单调效果,它应该只传递a
函数。
m
的unwrapped输出传递给return
,它重新包装它。 monadic性质保持不变。 所以它和原来的monad一样。
解包的值传递给f
然后重新包装。 monadic性质保持不变。 这是我们将普通函数转换为单子函数时的预期行为。
我没有这个法律的解释。 这确实表明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)关联性 - 一元组合是联想的(我喜欢KennyTM的答案)
两个身份法则基本上都是这样说的,但它们都是必需的,因为return
应该在绑定操作符的两边都有身份行为。
现在是第三法。 这个法则基本上说,当将函数提升到monad中时,Functor实例和Monad实例的行为方式都是相同的,并且它们都不是单向的。 如果我没有弄错,那么当一个单子服从其他三个法则并且函子实例服从函子法则时,那么这个声明将永远是真实的。
这很大一部分来自Haskell Wiki。 Typeclassopedia也是一个很好的参考。
与其他答案没有分歧,但它可能有助于将单子法看作实际描述两组属性。 正如约翰说的那样,你提到的第三条法则略有不同,但这里的其他条款可以如何拆分:
绑定到monad的函数与常规函数一样。
正如在约翰的回答中,所谓monad的Kleisli箭头是一个类型为a -> mb
的函数。 把return
当作id
和(<=<)
作为(.)
,并且monad定律是这些的翻译:
id . f
id . f
等于f
f . id
f . id
等同于f
(f . g) . h
(f . g) . h
等于f . (g . h)
f . (g . h)
一元效应序列附加列表。
大多数情况下,您可以将额外的一元结构看作与一元值相关的额外行为序列; 例如, Maybe
是为了Nothing
而“放弃”,为Just
而“继续前进”。 结合两个monadic动作然后基本连接他们所持有的行为序列。
在这个意义上, return
再次是一个标识 - 空行为,类似于一个空的行为列表 - (>=>)
是串联。 所以,单子法是这些的翻译:
[] ++ xs
等同于xs
xs ++ []
相当于xs
(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
这允许返回单值的函数正常工作。
链接地址: http://www.djcxy.com/p/42949.html