On SO an explanation is given why a Validation like in scalaz, cats (Scala), or Arrow (Kotlin) can't be a monad.
As far as I understand it's because they've modelled monads in terms of applicative functors and the desired behaviour of a Validation as applicative (gathering all invalids) is different from the desired behaviour of a Validation as monad (sequence validations and fail fast on the first invalid). As a result you need to convert a validation into an either (which is a monad) when you want the fail fast.
On https://groups.google.com/forum/#!msg/scalaz/IWuHC0nlVws/syRUkXJklWIJ, they mention the reason validation is not a monad, is because the following property would not hold:
x <|*|> y === x >>= (a => y map ((a, _)))
But looking at the definition of a monad, the property above is not part of the monad laws. So, is this a result of the fact that monads are implemented in terms of applicatives, or is the above property a prerequisite for being a monad?
This higher kind reasoning is all quit new to me, but in my limited understanding of FP, I could have a validation data type that has one kind of behaviour when used as an applicative (accumulating invalids) and another behaviour when used as a monad (failing fast).
Validation is not quite a monad as it doesn't quite follow the monad rules, even though it has the monad methods. Validation is similar to a Monad, and the difference is academic.
A proper monad must satisfy the three monad laws: left identity, right identity, and associativity. Together, left identity and right identity are know as simply identity.
You've got all the pieces right. Yes, a lawful monad instance for Validation
is possible. The problem is that it would yield two different Applicative
instances for Validation
: one accumulating the errors, the other one derived from the monad instance and failing fast. This would lead to typeclass incoherence: the program behavior depending on how the typeclass instance was arrived at.
The property you mention,
x <|*|> y === x >>= (a => y map ((a, _)))
can serve as the definition of <|*|>
in terms of >>=
and map
, and thus holds automatically for an Applicative derived from a Monad. The problem is that there's already a different Applicative with a different behavior of <|*|>
.
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