2012-02-08 32 views
6

nasıl mümkün scalaz böyle bir davranışa sahip uygulamaktır:Scalaz Doğrulama: agrega hatalar veya herhangi bir başarı dönmek

:

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

Çözümümün karmaşık görünüyor ve sanırım succint bunu yapmak için başka bir yol var

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] 
    ) 
    } 

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

Benim ikinci çözüm:

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

böyle kullanın:

val sum = v1 <+> v2 

cevap

6

Gerçekten de, >>*<< kullanabilirsiniz ikinci çözüme yakın Validation tanımlanan yöntem (acil çıkış?). Ancak, aynı zamanda başarıları bir araya getirmeye çalışacaktır, bunu düzeltmek isteyebilirsiniz.

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