Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 328
Jan Bols Avatar asked May 04 '18 11:05

Jan Bols


People also ask

Why Validation is not a monad?

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.

What are the monad laws?

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.


1 Answers

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

like image 94
Tomas Mikula Avatar answered Oct 19 '22 11:10

Tomas Mikula