Question

I have this implementation of scalaz Validation, it seems like that implicitly scalaz.Bind not in the scope, so for expression is not working. Here is the code:

import scalaz._
import Scalaz._

case class User(name: String, knowScala: Boolean, age: Int)

object PublicValidationSpec extends BasicValidation {
  def validate(user: User): Validation[String, String] = {
    for {
      b <- checkAge(user)
      c <- checkName(user)
    } yield s"Congrats, ${c.name}"
  }
}

trait BasicValidation {
  def checkName(user: User): Validation[String, User] = {
    if(user.name == "") "must have a name".fail else user.success
  }

  def checkAge(user: User): Validation[String, User] = {
    if(user.age < 3) "must be a valid age".fail else user.success
  }
}

the exception is

Error:(14, 25) Implicit not found: scalaz.Unapply[scalaz.Bind, 
scalaz.Validation[String,scalaz.validation.User]]. Unable to unapply type 
`scalaz.Validation[String,scalaz.validation.User]` into a type constructor of 
kind `M[_]` that is classified by the type class `scalaz.Bind`. Check that the 
type class is defined by compiling `implicitly[scalaz.Bind[type constructor]]` and 
review the implicits in object Unapply, which only cover common type 'shapes.'
           b <- checkAge(user)

Did i miss some implicit imports here ?
                        ^
Was it helpful?

Solution

Validation does not have a Bind defined for it.

In Scalaz 7.1.0-M5 (M6 too) Validation.flatMap is deprecated and in an attempt at subverting the warning, it looks like the precedence of flatMap is losing to scalaz.syntax.bind._, which is part of the Scalaz._ import. See this commit https://github.com/scalaz/scalaz/commit/2727b2451eba2aa159f3fbb62bf92790ac99dc7a. Try adding import scalaz.Validation.FlatMap._ or importing only the things you need, e.g.

import scalaz.Validation
import scalaz.syntax.validation._

I would recommend using something besides Validation though, as this will probably only cause you more problems in the future. See scalaz.\/ below.

This does compile with scalaz 7.0.5. Validation.flatMap is defined in 7.0.6 so it should compile with that version too. I would not use this functionality (Validation in for comprehensions) in new code though.

The scalaz powers that be have gona back and forth on deprecating Validation.flatMap for some time now. flatMap is what allows it to work in for comprehensions. flatMap is deprecated in the working branch though. There is a long background on this. See https://groups.google.com/forum/#!topic/scalaz/Wnkdyhebo2w.

TLDR - Validation is not a monad. Any possible implementation of Validation.flatMap will not match behavior of the Apply defined for Validation.

Use scalaz.\/ (a.k.a. disjunction) if you want to use something in for comprehensions. If you need to accumulate errors, the reason to use Validation over \/, convert to Validation and then back to \/.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top