Search code examples
scalaimplicitscala-cats

How to apply sequence function to List of ValidatedNel in cats?


I have the following code

sealed trait DomainValidation {
  def errorMessage: String
}
type ValidationResult[A] = ValidatedNel[DomainValidation, A]
val ai:ValidationResult[String] = "big".validNel
val bi:ValidationResult[String] = "leboski".validNel
val l = List(ai,bi)

I want to convert l to ValidationResult[List[String]]. I came across sequence functionality but I am unable to use cats sequence as some implicit has to be there which knows how to handle ValidationResult[A]. But I am unable figure out what exactly is needed. I wrote the following

object helper {
  implicit class hello[A](l: List[ValidationResult[A]]) {
    def mysequence: ValidationResult[List[A]] = {
     val m = l.collect { case Invalid(a) => Invalid(a) }
     if (m.isEmpty) l.map { case Valid(a) => a }.validNel
     else /* merge the NonEmpty Lists */
    }
  }
}

I am able to do l.mysequence. But how do I use cats sequence.

PS: I am a scala beginner. Having a hard time learning :). Forgive for any incorrect mentions.


Solution

  • The following should work as expected on Scala 2.12:

    import cats.data.ValidatedNel, cats.syntax.validated._
    
    // Your code:
    sealed trait DomainValidation {
      def errorMessage: String
    }
    type ValidationResult[A] = ValidatedNel[DomainValidation, A]
    val ai:ValidationResult[String] = "big".validNel
    val bi:ValidationResult[String] = "leboski".validNel
    val l = List(ai,bi)
    

    And then:

    scala> import cats.instances.list._, cats.syntax.traverse._
    import cats.instances.list._
    import cats.syntax.traverse._
    
    scala> l.sequence
    res0: ValidationResult[List[String]] = Valid(List(big, leboski))
    

    You don't show your code or explain what's not working, so it's hard to diagnose your issue, but it's likely to be one of the following problems:

    1. You're on Scala 2.11, where .sequence requires you to enable -Ypartial-unification in your compiler options. If you're using sbt, you can do this by adding scalacOptions += "-Ypartial-unification" to your build.sbt (assuming you're on 2.11.9+).
    2. You've omitted one of the necessary imports. You need at least the Traverse instance for List and the syntax for Traverse. The example code above includes the two imports you need, or you can just import cats.implicits._ and make your life a little easier.

    If it's not one of these two things, you'll probably need to include more detail in your question for us to be able to help.