I have 19 strings that need to be validated into various types. When all validate successfully, I would like to instantiate a class that represents a row of a spreadsheet (w
Suppose we have a case class (which could have more than twelve members):
case class Foo(a: Int, b: Char, c: Symbol, d: String)
And that we're representing errors as strings and have defined a type alias for convenience:
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)))
Which gives us what we want:
scala> println(good)
Success(Foo(1,a,'a,a))
scala> println(bad)
Failure(NonEmptyList(x, y))
In Haskell this would be much prettier—you'd just write:
Foo <$> goodA <*> goodB <*> goodC <*> goodD
Scala's weaker type inference requires us to write the arguments in the wrong order, unfortunately.