I'm fairly new to scalaz and I've started out with validations.
I have some validation functions of the form:
def validateXyz(...): ValidationNEL[String, String] = ...
I'm then using the applicative style to combine multiple validations and then call another function that also returns a validation:
(validateXyz(...) |@| validateAbc(...)) { (first, second) =>
otherFunction(first, second)
}
where,
def otherFunction(first: String, second: String): ValidationNEL[String, String] = ...
However, when calling the above the resulting type is:
val result: ValidationNEL[String, ValidationNEL[String, String]] = ...
I can unpack this by calling fold on the result with two functions, the first which just propagates the NEL as a fail and the second which just propagates its argument:
def propagateF(result: NonEmptyList[String]): ValidationNEL[String, String] = result.fail
def propagateV(result: ValidationNEL[String, String]) = result
result.fold(propagateF, propagateV)
// result type: ValidationNEL[String, String]
This works and returns the correct types and results. However it doesn't feel like the correct solution so I must be missing something. What do I need to do to avoid this horrible fold at the end?
What you are looking for here is monadic join
.
The thing is that Validation
itself is not really a monad, since the error side carries a Semigroup
structure that cannot be preserved by Monad
. But you can always drop down into the Either
monad if you need to. This functionality is provided by flatMap
.
(validateXyz(...) |@| validateAbc(...))(otherFunction).flatMap(x => x)
If you have an error on the outside, the result will be that error. If you have an error inside of a success, the result will be the inner error. Otherwise the result will be a success. Note the impossibility of having an error both on the inside and outside. This is why you have to use Applicative
rather than Monad
if you want to combine errors.
If 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