Accumulation of only validation errors in Scalaz

I am starting to work on functional programming, and I have the sequence ValidationNEL [A, B], and I would like to copy the errors to the new ValidationNEL [A, B]. It depends on the fact that B is a volatile data structure coming from old code, and therefore it would be oververbose to hold Seq [B].

I know from other posts that cumulation of errors and success are possible using the sequence method: Processing the Scalaz6 checklist

In my opinion, everything comes to writing the proper applicative and possibly the right Traverse.

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

How do i get started? When I tried to study the Scalaz source code to find out how to implement my applicator, I was very confused. I could not even find out which application allows to accumulate both failures and success in validation.

+5
source share
2 answers

Late to the party, but with Scalaz 7.0.4 we can do this:

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

Now that I understand your question a little better, this is pretty straight forward:

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

When you execute a Scala sequence, type problems arise, so you need to use a lambda type. Consistency is a good shortcut to go from Seq [Something [X]] to Something [Seq [X]]. Finally, we simply match success and get the last B from sequence B.

, , 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"))
+2

All Articles