2013-02-18 7 views
5

Jestem początkującym w pracy programowania funkcjonalnego i mam ciąg walidacjiNEL [A, B] i chciałbym zgromadzić błędy w nowym ValidationNEL [A, B]. Zależy to od faktu, że B jest zmienną strukturą danych pochodzącą ze starszego kodu, a zatem byłoby to oververbose do przechowywania Seq [B].Kumulowanie tylko błędów walidacji w Scalaz

wiem z innych stanowisk, które kumulując błędów i sukcesów jest możliwe dzięki metodzie sekwencji: Processing a list of Scalaz6 Validation

Z mojego zrozumienia, że ​​wszystko sprowadza się do pisania właściwego aplikacyjnych i może prawidłowego przemieszczenia.

trait MA[M[_], A] extends PimpedType[M[A]] with MASugar[M, A] { 

    def sequence[N[_], B](implicit a: A <:< N[B], t: Traverse[M], n: Applicative[N]): N[M[B]] = 
    traverse((z: A) => (z: N[B])) 

    def traverse[F[_],B](f: A => F[B])(implicit a: Applicative[F], t: Traverse[M]): F[M[B]] = 
    t.traverse(f, value) 
    } 

Jak zacząć? Kiedy próbowałem zajrzeć do kodu źródłowego Scalaz, aby dowiedzieć się, jak wdrożyć moją aplikację, byłem bardzo zdezorientowany. Nie byłem nawet w stanie dowiedzieć się, który aplikator pozwala gromadzić zarówno niepowodzenia, jak i powodzenie w walidacji.

+0

Czy próbujesz przejść od Seq [ValidtionNEL [A, B]] do ValidationNEL [A, Seq [B]] lub coś podobnego? – Noah

+0

no od Seq [ValidtionNEL [A, B]] do ValidationNEL [A, B] – Edmondo1984

+0

Tak więc ValidationNEL to tylko sprawdzanie poprawności [NonEmptyList [A], B], więc nie możesz zrobić tego, o co pytasz, chyba że możesz dodać B razem (ints , listy itd.). – Noah

Odpowiedz

3

późno do partii, ale jak Scalaz 7.0.4, możemy to zrobić:

def takeLastSuccess[A, B](seq: Seq[ValidationNel[A, B]]) = { 
     implicit val useLast = Semigroup.lastSemigroup[B] 
     seq reduceLeft (_ +++ _) 
    } 
2

Teraz rozumiem Twoje pytanie trochę lepiej, to jest całkiem prosta:

def takeLastSuccess[A, B](seq:Seq[ValidationNEL[A, B]]) = 
    seq.sequence[({type l[a] = ValidationNEL[A, a]})#l, B].map(_.last) 

Podczas sekwencjonowania Scala to ma pewne problemy z typów więc trzeba użyć typu lambda. Sekwencja to fajny skrót do przejścia z Seq [Something [X]] do Something [Seq [X]]. Wreszcie, po prostu mapujemy sukces i otrzymujemy ostatnie B z sekwencji B's.

pisali na przykład z the post you cited, oto co mam z REPL:

scala> import scalaz._, Scalaz._ 
import scalaz._ 
import Scalaz._ 

scala> type ExceptionsOr[A] = ValidationNEL[Exception, A] 
defined type alias ExceptionsOr 

scala> val successResults: Seq[ExceptionsOr[Int]] = Seq(
    |  "13".parseInt.liftFailNel, "42".parseInt.liftFailNel 
    | ) 
successResults: Seq[ExceptionsOr[Int]] = List(Success(13), Success(42)) 

scala> val failResults: Seq[ExceptionsOr[Int]] = Seq(
    |  "13".parseInt.liftFailNel, "a".parseInt.liftFailNel, "b".parseInt.liftFailNel 
    | ) 
failResults: Seq[ExceptionsOr[Int]] = List(Success(13), Failure(NonEmptyList(java.lang.NumberFormatException: For input string: "a")), Failure(NonEmptyList(java.lang.NumberFormatException: For input string: "b"))) 

scala> def takeLastSuccess[A, B](seq:Seq[ValidationNEL[A, B]]) = seq.sequence[({type l[a] = ValidationNEL[A, a]})#l, B].map(_.last) 
takeLastSuccess: [A, B](seq: Seq[scalaz.Scalaz.ValidationNEL[A,B]])scalaz.Validation[scalaz.NonEmptyList[A],B] 

scala> takeLastSuccess(successResults) 
res0: scalaz.Validation[scalaz.NonEmptyList[Exception],Int] = Success(42) 

scala> takeLastSuccess(failResults) 
res1: scalaz.Validation[scalaz.NonEmptyList[Exception],Int] = Failure(NonEmptyList(java.lang.NumberFormatException: For input string: "a", java.lang.NumberFormatException: For input string: "b")) 
+0

To jest podobne rozwiązanie do tego, co już zaimplementowałem. Idealnym rozwiązaniem byłoby dostarczenie prawidłowej Aplikacji, aby metoda sekwencji działała tak, jak chcę – Edmondo1984

Powiązane problemy