Why isn't Validation a Monad?
Asked Answered
R

2

29

an example use case:

def div2(i: Int): Validation[String, Int] = 
    if (i%2 == 0) Validation.success(i/2)
    else Validation.failure("odd")

def div4(i: Int) = for {
    a <- div2(i)
    b <- div2(a)
} yield b

error: Unable to unapply type scalaz.Validation[String,Int] into a type constructor of kind M[_] that is classified by the type class scalaz.Bind

I guess the error is caused by the compiler can't find a Monad instance for Validation[String, Int]

I can make one for myself, like:

object Instances {
implicit def validationMonad[E] = new Monad[({type L[A] = Validation[E, A]})#L] {
    override def point[A](a: => A) =
        Validation.success(a)
    override def bind[A, B](fa: Validation[E, A])(f: A => Validation[E, B]) =
        fa bind f
}
}

but why doesn't Validation have it already? after all, Validation already has the bind method defined.

moreover, I can't have import Validation._ and import Instances._ together anymore (this took me looong to figure out...), because of another complicated error...
ambiguous implicit values: something like both validationMonad (my instance), and method ValidationInstances1 in trait ValidationInstances2... both match some Functor of Validation...

should I modify the source of scalaz? or I'm completely missing something~?
please help~

I'm using scalaz 7.0.0-M2

Retiform answered 31/8, 2012 at 8:40 Comment(0)
A
23

As discussed in the Scalaz group, the problem seems to be that ap would accumulate errors whereas (pseudo-)monadic composition would only operate on the value part of Validation.

Therefore, one cannot be expressed in terms of the other and thus no monad instance exists for Validation.

Archpriest answered 31/8, 2012 at 9:12 Comment(4)
hm... maybe I'm not too well in functional programming, I still couldn't appreciate why the property (in the discussion) should hold... but I guess this already answered my question here, thanks~Retiform
but as a side question, is there no way out for my use case? other than defining the Monad instance myself~? is there any bad side to my approch?Retiform
@chris If you don’t care about automatic appending of failure, an obvious choice would be to switch completely over to scalaz.\/ (Scalaz’s right-biased replacement for Either) which has the semantics you want and may therefore be less confusing for other people. (Implementing a rule which basically breaks monad and applicative laws may work perfectly well and predictable but it may turn out to be a bit confusing nonetheless.)Archpriest
@chris I would say that there is only one tiny thing bad with your approach which is that some people would find it surprising that the monad laws are violated. But, intuitively, in my opinion it actually makes perfect sense to violate the monad laws in this case.Jornada
I
6

The issue is that the applicative functor as implied by the monad does not equal the actual applicative functor

Incoercible answered 31/8, 2012 at 10:0 Comment(3)
could you please explain futhur what is the implied and what is the actual? I don't know much about these typeclass thing...Retiform
respectful bump to @IncoercibleConfirmation
You can lawfully derive the applicative interface from monadic bind/chain (it's just a chain operation to get at the inner value (a function), and then mapping over the second applicative using that function). But if you actually implement that though, you'd end up with the applicative behavior you'd expect from an Either type, not the one you'd expect from Validation.Redstart

© 2022 - 2024 — McMap. All rights reserved.