I need a combinator to transform a List[ValidationNel[A, Option[B]]]
into a ValidationNel[A, List[B]]
to sequence the validation and, in case of success, flatten that crap.
Here is the code :
def sequenceAndFlatten[A,B](valid: List[ValidationNel[A, Option[B]]]) : ValidationNel[A, List[B]] =
valid.sequenceU.map(_.flatten)
Is there a better way ?
We can use traverseM
:
Quoting the traverseM
documentation ( join
is the Scalaz name for flatten
) :
A version of traverse where a subsequent monadic join is applied to the inner result.
sequence
is the same as traverse(identity)
.
So traverseM(identity)
should be similar to sequence.map(_.flatten)
, but flatten
uses an implicit conversion from Option
to List
while Scalaz will only flatten monads of the same type, so we need to convert the Option
to List
explicitly: traverseM(_.map(_.toList))
.
A problem with using traverseM
is that we cannot use Unapply
, like with your sequenceU
. We will need to give the compiler some help and specify the type parameters (using a type lambda) ourselves.
import scalaz.ValidationNel
import scalaz.std.list._
import scalaz.syntax.traverse._
def seqFlat[A,B](valid: List[ValidationNel[A, Option[B]]]): ValidationNel[A, List[B]] =
valid.traverseM[({type l[x] = ValidationNel[A, x]})#l, B](_.map(_.toList))
Which gives the same result as your sequenceAndFlatten
:
import scalaz.std.option._
import scalaz.syntax.std.option._
import scalaz.syntax.validation._
val validations =
List(1.some.successNel[String], 2.some.successNel, none[Int].successNel)
sequenceAndFlatten(validations)
// scalaz.ValidationNel[String,List[Int]] = Success(List(1, 2))
seqFlat(validations)
// scalaz.ValidationNel[String,List[Int]] = Success(List(1, 2))
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.