Search code examples
monadsscalazapplicativescala-catsarrow-kt

Why would validation break the monad laws?


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).


Solution

  • 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 <|*|>.