简体   繁体   中英

Convert a ValidationNel[A, List[B]] into ValidationNel[A, NonEmptyList[B]]

I have written a combinator to convert a ValidationNel[A, List[B]] into ValidationNel[A, NonEmptyList[B]] that returns a Failure when the List is empty.

  def nonEmpty[A, B](valid : ValidationNel[A, List[B]], fail : => A) : ValidationNel[A, NonEmptyList[B]] =
    valid match {
      case Failure(f) => f.failure[NonEmptyList[B]]
      case Success(s) =>
        if (!s.isEmpty) NonEmptyList(s.head, s.tail:_*).successNel[A]
        else fail.failureNel[NonEmptyList[B]]
    }

Is there a better way ?

We can improve your nonEmpty function in two ways :

  • Scalaz can turn a List into an Option[NonEmptyList] using toNel .
  • Your pattern match on ValidationNel is similar to a flatMap , but Validation doesn't have a flatMap operation since it is an Applicative and not a Monad . Scalaz provides some easy functions to convert between Validation and \\/ (also known as disjunction), so we can use \\/ 's flatMap .

Your nonEmpty function then could look like :

import scalaz.{ValidationNel, NonEmptyList}
import scalaz.syntax.std.list._
import scalaz.syntax.std.option._
import scalaz.syntax.nel._

def nonEmpty[A, B](valid: ValidationNel[A, List[B]], 
                   fail: => A): ValidationNel[A, NonEmptyList[B]] =
  valid.disjunction.flatMap(_.toNel toRightDisjunction fail.wrapNel).validation

Which you could use as :

import scalaz.syntax.validation._

nonEmpty(List(1,2).success, "test")
// scalaz.ValidationNel[String,scalaz.NonEmptyList[Int]] = 
//   Success(NonEmptyList(1, 2))

nonEmpty(List().success, "list is empty")
// scalaz.ValidationNel[String,scalaz.NonEmptyList[Nothing]] =
//   Failure(NonEmptyList(list is empty))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM