Мы можем использовать traverseM
:
Цитирование документации traverseM
(join
это имя Scalaz для flatten
):
версия траверсы, где последующее монадические присоединиться применяются к внутреннему результат.
sequence
такое же, как traverse(identity)
.
Так traverseM(identity)
должен быть похож на sequence.map(_.flatten)
, но flatten
использует неявное преобразование из Option
в List
в то время как Scalaz только придавить монады одного и того же типа, так что нам нужно преобразовать Option
в List
явно: traverseM(_.map(_.toList))
.
Проблема с использованием traverseM
заключается в том, что мы не можем использовать Unapply
, как с вашим sequenceU
. Нам нужно будет предоставить компилятору некоторую помощь и указать параметры типа (используя тип лямбда).
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))
Что дает тот же результат, как ваш 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))