Reputation: 6431
I like monad transformers. For example, I can combine nicely two future optional values like this:
val val1:OptionT[Task, Int] = ???
val val2:OptionT[Task, Int] = ???
val sum = for {
one ← val1
two ← val2
} yield (one + two)
Since Validation
doesn't have a Monad[_]
instance, I can't use similar syntax for it. What is the best way, how to sum these two:
val val3:Task[ValidationNel[Throwable,Int]] = ???
val val4:Task[ValidationNel[Throwable,Int]] = ???
Upvotes: 3
Views: 281
Reputation: 13959
If you define a semigroup instance for Int
, you can just add the validations together to get back one Task[ValidationNel[Throwable,Int]]
:
val sum2 = for {
three ← val3
four ← val4
} yield three +|+ four
Upvotes: 1
Reputation: 1833
You are probably looking for way to accumulate errors or compute result. You may be interested in macculkin operator, I mean a pipe at pipe or |@|
(choose the name you like most) ;)
Example of usage. See how errors are accumulated (OMG! and Holly mum! are included in result.
import scalaz._
import Scalaz._
val v1: ValidationNel[Throwable, Int] = 1.successNel
val v2: ValidationNel[Throwable, Int] = new RuntimeException("OMG!").failNel
val v3: ValidationNel[Throwable, Int] = new RuntimeException("Holly mom!").failNel
val sum : ValidationNel[Throwable, Int] = (v1 |@| v2 |@| v3 ) (_ + _ + _)
//scala> sum: scalaz.ValidationNel[Throwable,Int] = Failure(NonEmptyList(java.lang.RuntimeException: OMG!, java.lang.RuntimeException: Holly mom!))
The often made mistake is when you choose to use for comprehension or map functions. When you decide follow such way you will not able to acumulate errors. Only OMG! is accumulated. See below:
for( val1 <- v1;
val2 <- v2;
val3 <- v3
) yield(val1 + val2 + val3)
//res0: scalaz.Validation[scalaz.NonEmptyList[Throwable],Int] = Failure(NonEmptyList(java.lang.RuntimeException: OMG!))
Upvotes: 2