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

时间:2014-10-16 00:00:48

标签: scala validation scalaz

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

def validateProduct(product: Option[Product]): ValidationNel[String, Product] = ???

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

 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?
    ???
  }

感谢任何帮助

2 个答案:

答案 0 :(得分:16)

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

val result: ValidationNel[String, List[Product]] =
  products.toList.traverseU(validateProduct)

请注意,我已将Seq转换为List,因为原始Seq没有类型类实例,我使用{{1}而不是traverseU因为Scala的类型推断对于非平凡类型构造函数(例如traverse

)不起作用

答案 1 :(得分:7)

你可以使用fold with 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)