Это потому, что ваш Writer
нарушает законы монады.Посмотрите на этот закон:
-- forall (f :: a -> Writer m b) (x :: a).
return x >>= f = f x
-- basically f (id x) = f x, which we should agree is pretty important!
Но, увы, он не выполняется!let f = undefined
!(или f = const undefined
; они неразличимы, если вы не используете seq
)
return x >>= undefined
= Writer mempty x >>= undefined
= let (Writer m y) = undefined
in Writer (mempty <> m) y
= Writer (mempty <> undefined) undefined
Тем не менее, по закону,
return x >>= undefined
= undefined x
= undefined
Это не эквивалентно, поэтому ваш ленивыйMonad
экземпляр является незаконным (и да, я полагаю, так же, как и в mtl
).Тем не менее, Быстрые и бесполезные рассуждения нравственно правильны , поэтому мы обычно просто принимаем это.Идея состоит в том, что ленивая Writer
монада, как правило, следует законам, которые она должна соблюдать, до тех пор, пока вы сохраняете из нее бесконечные или нижние значения, но она ломается в этих крайних случаях.Напротив, строгое выполнение полностью законно, и поэтому оно находится в base
.Однако, как вы обнаружили, когда ленивые Writer
s нарушают закон, они делают это полезным способом, поэтому мы помещаем ленивую реализацию в mtl
.
Вот демонстрационная версия этого поведения .Обратите внимание, что ленивая версия выдает Writer "
на выходе до взрыва, в то время как строгая версия и спецификация, установленные законом, не делают этого.