如果你违反monad法则,你会怎么样?
编译器或者库中更“本土”的部分(IO或可以使用黑魔法和实现的函数)是否对这些规律做出了假设? 打破他们会导致不可能发生?
或者他们只是expression了一种编程模式 – 也就是说,你打扰他们的唯一一个会使用你的代码的人,并不希望你如此粗心大意?
编译器不会对法律做出任何假设,但是,如果您的实例不遵守法律,它不会像单子一样 – 它会做奇怪的事情,并以其他方式显示给您的用户无法正常工作(例如,价值观,或以错误的顺序评估事物)。
另外,假设monad法则持有的用户可能做出的重构显然不是很合理。
单子法只是实例预期要遵循的附加规则,超出了types系统中可以expression的内容。 就Monad
表示编程模式而言,法律是这种模式的一部分 。 这样的法则也适用于其他types: Monoid
与Monad
有着非常相似的规则,并且通常期望Eq
例子将遵循平等关系所期望的规则等等。
因为这些法律在某种意义上是types类的“一部分”,所以其他代码期望它们将持有并相应地采取行动是合理的。 行为不当的情况可能违反了客户代码的逻辑假设,导致错误,错误归咎于实例,而不是使用它的代码。
简而言之,“打破单子法”通常应被理解为“写出错误的代码”。
我将用一个涉及另一个types的例子来说明这一点,这个例子是由Daniel Fischer在haskell-cafe邮件列表中给出的。 (希望)众所周知的是,标准库包含一些行为不当的实例,即浮点types的Eq
和Ord
。 当您涉及NaN时,您可能会猜到,这种不正当行为会发生。 考虑以下数据结构:
> let x = fromList [0, -1, 0/0, -5, -6, -3] :: Set Float
0/0
产生一个NaN,这违反了Data.Set.Set
所做的关于Ord
实例的假设。 这个Set
是否包含0
?
> member 0 x True
是的,当然是的,它就在那里一目了然! 现在,我们在Set
插入一个值:
> let x' = insert (0/0) x
这个Set
仍然包含0
,对吧? 毕竟,我们并没有删除任何东西。
> member 0 x' False
哦,哦 。 噢亲爱的。
对于使用更“主stream”语言的人来说,这就像实现一个接口一样,但这样做是错误的。 例如,假设你正在使用提供IShape接口的框架,并且实现它。 然而,你的draw()方法的实现根本不会绘制,而只是实例化你的类的1000多个实例。
这个框架会尝试使用你的IShape,并用它做合理的事情,上帝知道会发生什么。 这将是一个有趣的火车残骸观看。
如果你说你是一个Monad,你是“宣布”你遵守合同和法律。 其他代码将相信您的声明,并相应采取行动。 既然你撒谎了,事情就会以不可预知的方式出错。