5

I am a beginner in the work of functional programming and I have a sequence of ValidationNEL[A,B] and I would like to accumulate the errors into a new ValidationNEL[A,B]. This depends on the fact that B is a mutable data structure coming from legacy code, and so it would be oververbose to hold a Seq[B].

I know from other posts that cumulating errors and success is possible through the sequence method: Processing a list of Scalaz6 Validation

From my understanding it all comes to writing a proper Applicative and maybe a proper 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 start? When I tried to look into Scalaz source code to find out how to implement my Applicative, I got extremely confused. I was not even able to find out which applicative allows accumulating both failures and success in Validation.

Community
  • 1
  • 1
Edmondo
  • 19,559
  • 13
  • 62
  • 115
  • Are you trying to go from Seq[ValidtionNEL[A, B]] to ValidationNEL[A, Seq[B]] or something similar? – Noah Feb 19 '13 at 00:35
  • no from Seq[ValidtionNEL[A, B]] to ValidationNEL[A,B] – Edmondo Feb 19 '13 at 06:03
  • So ValidationNEL is just Validation[NonEmptyList[A], B] so you can't do what your asking unless you can add B's together (ints, lists, etc). – Noah Feb 19 '13 at 13:58
  • of course this can be done. I want to keep the last B of my Seq[ValidationNEL[A,B]] and concatenate all the nonEmptyList[A] – Edmondo Feb 19 '13 at 19:00

2 Answers2

3

Late to the party, but as of 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 (_ +++ _)
  }
AlecZorab
  • 672
  • 1
  • 5
  • 14
2

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 sequence this Scala has some trouble with the types so you need to use a type lambda. Sequence is a nice shortcut to go from Seq[Something[X]] to Something[Seq[X]]. Finally, we just map the success and get the last B from the sequence of B's.

Going off the example from the post you cited, here's what I get from the 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"))
Community
  • 1
  • 1
Noah
  • 13,821
  • 4
  • 36
  • 45
  • This is similar solution to what I have already implemented. The ideal solution would be to provide a correct Applicative for the sequence method to work as I desire – Edmondo Feb 20 '13 at 15:51