Законы монады - это просто дополнительные правила, которым должны следовать экземпляры, помимо того, что может быть выражено в системе типов.Поскольку Monad
выражает шаблон программирования, законы являются частью этого шаблона.Такие законы применяются также и к другим классам типов: Monoid
имеет очень похожие правила к Monad
, и обычно ожидается, что экземпляры Eq
будут следовать правилам, ожидаемым для отношения равенства, среди других примеров.
Поскольку эти законы в некотором смысле являются «частью» класса типов, для другого кода должно быть разумным ожидать, что они будут выполняться и действовать соответственно.Таким образом, неправильное поведение экземпляров может нарушать допущения, сделанные логикой клиентского кода, что приводит к ошибкам, вина за которые должным образом размещается в экземпляре, а не к коду, использующему его.быть прочитанным как «написание глючного кода».
Я проиллюстрирую этот момент на примере, включающем другой класс типов, модифицированный по сравнению с классом, данным Дэниелом Фишером в списке рассылки haskell-cafe.(Надеюсь) хорошо известно, что стандартные библиотеки включают в себя несколько некорректно работающих экземпляров, а именно Eq
и Ord
для типов с плавающей запятой.Как вы можете догадаться, неправильное поведение происходит, когда задействован NaN.Рассмотрим следующую структуру данных:
> let x = fromList [0, -1, 0/0, -5, -6, -3] :: Set Float
Где 0/0
создает NaN, что нарушает предположения о Ord
экземплярах, сделанные Data.Set.Set
.Содержит ли это Set
0
?
> member 0 x
True
Да, конечно, так оно и есть, на виду!Теперь мы вставляем значение в Set
:
> let x' = insert (0/0) x
Это Set
все еще содержит 0
, верно?В конце концов, мы ничего не удалили.
> member 0 x'
False
... о .Ох, дорогой.