Scalaz验证:将验证序列转换为单个验证

tri*_*rNZ 14 validation scala scalaz

我正在使用scalaz验证,并有一些代码来验证产品.

def validateProduct(product: Option[Product]): ValidationNel[String, Product] = ???
Run Code Online (Sandbox Code Playgroud)

给定一个产品列表,我希望得到一个包含整个列表的验证作为成功值或验证错误列表.似乎某种折叠应该这样做,但我不确定组合功能应该是什么.

 def validateProducts(products: Seq[Option[Product]]): ValidationNel[String, Seq[Product]] = {
    val listOfValidations: Seq[ValidationNel[String, Product]] = products.map(validateProduct _)
    val validatedList:ValidationNel[Seq[String], Seq[Product]] = ??? // what to do here?
    ???
  }
Run Code Online (Sandbox Code Playgroud)

任何帮助表示赞赏

Hug*_*ugh 17

如果不是ValidationNel[List[String], List[Product]]你想要的ValidationNel[String, List[Product]](即同一列表中的所有失败),你可以使用traverse:

val result: ValidationNel[String, List[Product]] =
  products.toList.traverseU(validateProduct)
Run Code Online (Sandbox Code Playgroud)

请注意,我已将转换Seq为a,List因为没有raw的类型类实例Seq,而且我使用traverseU而不是traverse因为Scala的类型推断对于非平凡类型构造函数不太适用ValidationNel


Eug*_*nev 7

您可以使用折叠与applicative

  import scalaz.syntax.validation._
  import scalaz.syntax.applicative._

  case class Product(name: String)

  val allGood = Seq(
    Product("a").successNel[String],
    Product("b").successNel[String]
  )

  val aggregated: ValidationNel[String, Seq[Product]] = 
    allGood.foldLeft(Seq.empty[Product].successNel[String]) {
    case (acc , v) => (acc |@| v)(_ :+ _)
  }

  println(aggregated)
Run Code Online (Sandbox Code Playgroud)