From the documentation of the validation
package:
The
AccValidation
data type is isomorphic toEither
, but has an instance ofApplicative
that accumulates on the error side. That is to say, if two (or more) errors are encountered, they are appended using aSemigroup
operation.As a consequence of this
Applicative
instance, there is no correspondingBind
orMonad
instance.AccValidation
is an example of, "An applicative functor that is not a monad."
It isn't evident to me why this is a consequence. I can imagine a Monad
instance for AccValidation
that behaves like Either
- What would make this unlawful?
The (<*>) = ap
exigence can be stated explicitly in terms of (>>=)
:
u <*> v = u >>= \f -> fmap f v -- [1]
Now, given the Functor
and Applicative
instances for AccValidation
, we have:
fmap _ (AccFailure e) = AccFailure e -- [2]
AccFailure e1 <*> AccFailure e2 = AccFailure (e1 <> e2) -- [3]
If we make u = AccFailure e1
and v = AccFailure e2
in [1], we get:
AccFailure e1 <*> AccFailure e2 = AccFailure e1 >>= \f -> fmap f (AccFailure e2)
Substituting [2] and [3] into that leads us to:
AccFailure (e1 <> e2) = AccFailure e1 >>= \_ -> AccFailure e2 -- [4]
The problem is that it is impossible to write a (>>=)
such that [4] holds. The left-hand side depends on an e2
value which must originate, on the right-hand side, from applying \_ -> AccFailure e2 :: Semigroup e => a -> AccValidation e b
. However, there is nothing to which it can be applied -- in particular, e1
has the wrong type. (See the final two paragraphs of Cactus' answer for further discussion of this point.) Therefore, there is no way of giving AccValidation
a Monad
instance which is consistent with its Applicative
one.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With