The monad laws are simply additional rules that instances are expected to follow, beyond what can be expressed in the type system. Insofar as Monad
expresses a programming pattern, the laws are part of that pattern. Such laws apply to other type classes as well: Monoid
has very similar rules to Monad
, and it's generally expected that instances of Eq
will follow the rules expected for an equality relation, among other examples.
Because these laws are in some sense "part of" the type class, it should be reasonable for other code to expect they will hold, and act accordingly. Misbehaving instances may thus violate assumptions made by client code's logic, resulting in bugs, the blame for which is properly placed at the instance, not the code using it.
In short, "breaking the monad laws" should generally be read as "writing buggy code".
I'll illustrate this point with an example involving another type class, modified from one given by Daniel Fischer on the haskell-cafe mailing list. It is (hopefully) well known that the standard libraries include some misbehaving instances, namely Eq
and Ord
for floating point types. The misbehavior occurs, as you might guess, when NaN is involved. Consider the following data structure:
> let x = fromList [0, -1, 0/0, -5, -6, -3] :: Set Float
Where 0/0
produces a NaN, which violates the assumptions about Ord
instances made by Data.Set.Set
. Does this Set
contain 0
?
> member 0 x
True
Yes, of course it does, it's right there in plain sight! Now, we insert a value into the Set
:
> let x' = insert (0/0) x
This Set
still contains 0
, right? We didn't remove anything, after all.
> member 0 x'
False
...oh. Oh, dear.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…