Scalaz验证:将一系列验证转换为单个验证

14

我正在使用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个回答

17

如果您想要一个ValidationNel[String,List[Product]]而不是ValidationNel[List[String],List[Product]](即将所有失败放在同一个列表中),您可以使用traverse

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

请注意,我已将Seq转换为List,因为原始的Seq没有类型类实例,并且我使用traverseU而不是traverse,因为Scala的类型推断对于非平凡类型构造函数(例如ValidationNel)并不完全适用。


非常干净的解决方案 - Ana

7

您可以使用applicative与fold

  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)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接