Cannot figure out if it is possible to write something like this using Scalaz 7. I have tried to express myself with the comments inside the code block.
def validate1(p: String) = ValidationNel[String, Value] = ...
def validate2(p: String) = ValidationNel[String, Value] = ...
validateCombination(p1: String, p2: String) = {
// I would like to write something like
(validate1(p1) |@| validate2(p2)) { (v1, v1) =>
// And validate the combinations here and return successNel of failNel
}
}
def validate(p1: String, p2: String, p3: String) = {
(validateCombination(p1, p2) |@| validate1(p3)) { (v1, v2, v3) =>
// Notice the three parameters I want to have here
}
}
I just end up with different types of confusing compilation errors in validateCombinations or just 2 parameters for the applicative functor I get inside validate function, one of them being of type ValidationNel[...].
You could use .flatMap(identity)
in method validateCombination
to produce ValidationNel[String, (Value, Value)]
and pattern matching
in method validate
like this:
def validateCombination(p1: String, p2: String): ValidationNel[String, (Value, Value)] = {
// I would like to write something like
(validate1(p1) |@| validate2(p2)) { (v1, v1) =>
(v1, v2).successNel[String]
}.flatMap(identity)
}
def validate(p1: String, p2: String, p3: String) = {
(validateCombination(p1, p2) |@| validate1(p3)) { case ((v1, v2), v3) =>
// Notice the three parameters I want to have here
}
}
flatMap(identity)
Normally you would use method flatten
on nested containers to get M[T]
from M[M[T]]
. It works on Future
, Option
, Try
, collections and so on.
In this case type M[T] = ValidationNel[String, T]
.
I don't know why there is no method flatten
in Validation
, but you could always use flatMap(identity)
instead of flatten
.
match
As Ben James noted, flatMap
on Validation
is dubious. You could always use match
instead of it:
(validate1(p1) |@| validate2(p2)) { (v1, v1) =>
(v1, v2).successNel[String]
} match {
case Success(s) => s
case Failure(f) => Failure(f)
}
pattern matching
Pattern matching is the common way to deal with tuples. For instance it's vary useful with foldLeft
method, like foldLeft(1 -> 2){ case ((a, b), c) => ??? }
.
If you find yourself using getters _N
on Tuple
you are probably should use pattern matching.
for comprehension
As Daniel C. Sobral noted for comprehension could be easier to understand.
You could use it in your validate
method like this:
def validate(p1: String, p2: String, p3: String) = {
for{
(v1, v2) <- validateCombination(p1, p2) // pattern matching
v3 <- validate1(p3)
} yield ??? // Your code here
}
It involves pattern matching without case
keyword.
Note that for comprehension calls flatMap
on validateCombination(p1, p2)
, so you'll lost error messages from validate1(p3)
in case validateCombination(p1, p2)
is Failure
. On the contrary, |@|
collects all error messages from both sides.