Scalaz验证:汇总错误或返回任何成功

时间:2012-02-08 15:01:34

标签: scala scalaz

如何用scalaz实现这样的行为:

"Fail1".failNel[Int] and "Fail2".failNel[Int] to Failure("Fail1", "Fail2")
"Fail1".failNel[Int] and 100.successNel[String] to Success(100)

我的解决方案看起来很复杂,我想还有其他一些方法可以解决这个问题:

  def aggregateErrorsOrSuccess(v1: ValidationNEL[String, Int], 
                               v2: ValidationNEL[String, Int]) = {
    v2.fold(
      nl => (nl.fail[Int] |@| v1) {(i1, i2) => (/*actually should never happen*/)},
      res => res.successNel[String]
    )
  }

=====================

我的第二个解决方案:

implicit def nel2list[T](nl: NonEmptyList[T]) = nl.head :: nl.tail;

implicit def ValidationNELPlus[X]: Plus[({type λ[α]=ValidationNEL[X, α]})#λ] = new      Plus[({type λ[α]=ValidationNEL[X, α]})#λ] {
def plus[A](a1: ValidationNEL[X, A], a2: => ValidationNEL[X, A]) = a1 match {
    case Success(_) => a1
    case Failure(f1) => a2 match {
      case Success(_) => a2
      case Failure(f2) => (f1 <::: f2).fail[A]
    }
  }
}

像这样使用:

val sum = v1 <+> v2

1 个答案:

答案 0 :(得分:6)

确实,您可以使用>>*<<中定义的Validation(紧急退出?)方法,该方法与您的第二个解决方案接近。然而,它也会尝试聚合成功,你可能想要调整它。

def >>*<<[EE >: E: Semigroup, AA >: A: Semigroup](x: Validation[EE, AA]): Validation[EE, AA] = (this, x) match {
  case (Success(a1), Success(a2)) => Success((a1: AA) ⊹ a2)
  case (Success(a1), Failure(_)) => Success(a1)
  case (Failure(_), Success(a2)) => Success(a2)
  case (Failure(e1), Failure(e2)) => Failure((e1: EE) ⊹ e2)
}