If I have multiple operations that return a Validation[E, _] of something with a fixed error type I can use them in a for-comprehension. For example:
val things: Validation[E, (Int, Double)] = for {
i <- getValidationOfInt
d <- getValidationOfDouble
} yield (i, d)
What about if the error types are different? Suppose I read from HTTP and want to convert the string response into an Int.
import scalaz._; import Scalaz._
object ValidationMixing {
class HttpError
def getFromHttp: Validation[HttpError, String] = ???
def parseInt(json: String): Validation[Throwable, Int] =
Validation.fromTryCatchNonFatal(Integer.parseInt(json))
val intParsedFromHttp: Validation[Any, Int] = for {
s <- getFromHttp
i <- parseInt(s)
} yield i
}
This compiles, but only because the error type of the Validation is Any, being a supertype of Throwable and HttpError. This isn't very helpful.
I can think of various ways of representing such a combined error type that are more useful than Any (e.g. Validation[Error1 \/ Error2, Result] to store either, Validation[String, Result] translating to an error message, etc) but they all have drawbacks.
Is there an idiomatic way to do this?
Since nobody has had a better idea I'll leave my answer for future reference.
As said in the comment the best way is to create a error hierarchy:
trait GenericError { /* some commond fields */}
case class MyNumericError(/* fields */)
and then use leftMap on a validation to generate appropriate errors:
Validation.fromTryCatchNonFatal(...).leftMap(t => MyNumericError(...))
This approach has two advantages
Validation[GenericError, T] so not having different types on the left part of that validationIf you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With