Returning NonEmptyList `sealed trait`'s w/ scalaz.Validation

103 views Asked by At

Given the following code:

object Person {

    override def makePerson(name: String, age: Int, gender: Gender): 
              Validation[NonEmptyList[InvalidPersonError], Person] =
        (validateName(name) |@| validateAge(age)) {_ ++ _} 

    private def validateName(name: String): 
       Validation[NonEmptyList[InvalidPersonError], String] = 
        if(name.nonEmpty) name.successNel else InvalidName.failureNel

    private def validateAge(age: Int): Validation[NonEmptyList[InvalidPersonError], Int] = 
        if(age >= 0) age.successNel else InvalidAge.failureNel

    sealed trait Gender
    case object Male extends Gender
    case object Female extends Gender

    sealed trait InvalidPersonError
    case object InvalidName extends InvalidPersonError
    case object InvalidAge extends InvalidPersonError
}

case class Person(name: String, age: Int, gender: Person.Gender)

However, I get a compile-time error when trying to put two InvalidPersonError's into a NonEmptyList:

[error] ...\Person.scala:9: type mismatch;
[error]  found   : Int
[error]  required: scala.collection.GenTraversableOnce[?]
[error]                 (validateName(name) |@| validateAge(age)) {_ ++ _}
[error]            

How can I combine the validation errors to fix this compile-time error?

1

There are 1 answers

0
Travis Brown On BEST ANSWER

You don't need to describe how to combine errors—that's taken care of by ValidationNel's applicative functor via the Semigroup instance for NonEmptyList. The argument to the applicative builder should instead indicate how to create people:

def makePerson(name: String, age: Int, gender: Gender):
  Validation[NonEmptyList[InvalidPersonError], Person] =
    (validateName(name) |@| validateAge(age))(Person(_, _, gender))

This will accumulate errors correctly.