Scalaz: how can I accumulate errors or apply a function for validations with different types?

I have 19 lines that need to be checked for different types. When everything is checked successfully, I would like to create an instance of a class representing the row of the table (where not all columns are of the same type).

If one or more lines are not checked, I would like to have errors accumulated in NonEmptyList.

If there were 12 or fewer items, I could use | @ | or apply 12. If I use a for expression for an expression, it does not work fast and accumulation does not occur.

I can execute a sequence of crashes when the for statement does not work, but that means that I loop twice. Is there a way to use scalaz to pull every validation success into a variable (as it would if I used a for expression to instantiate the class) while accumulating all the failures?

+7
source share
1 answer

Suppose we have a case class (which can contain more than twelve members):

case class Foo(a: Int, b: Char, c: Symbol, d: String) 

And we present the errors as strings and for convenience we have defined an alias of the type:

 type ErrorOr[A] = ValidationNel[String, A] 

We also have some validation results:

 val goodA: ErrorOr[Int] = 1.success val goodB: ErrorOr[Char] = 'a'.success val goodC: ErrorOr[Symbol] = 'a.success val goodD: ErrorOr[String] = "a".success val badA: ErrorOr[Int] = "x".failNel val badC: ErrorOr[Symbol] = "y".failNel 

Now we can write:

 val foo = (Foo.apply _).curried val good: ErrorOr[Foo] = goodD <*> (goodC <*> (goodB <*> (goodA map foo))) val bad: ErrorOr[Foo] = goodD <*> (badC <*> (goodB <*> (badA map foo))) 

What gives us what we want:

 scala> println(good) Success(Foo(1,a,'a,a)) scala> println(bad) Failure(NonEmptyList(x, y)) 

In Haskell, it will be much prettier - you just write:

 Foo <$> goodA <*> goodB <*> goodC <*> goodD 

Scala's weaker type inference requires that we, unfortunately, write arguments in the wrong order.

+10
source

All Articles