我需要一个组合器将List[ValidationNel[A, Option[B]]]
变换为ValidationNel[A, List[B]]
以对验证进行排序,并且在成功的情况下,将该废话变平。
以下是代码:
def sequenceAndFlatten[A,B](valid: List[ValidationNel[A, Option[B]]]) : ValidationNel[A, List[B]] =
valid.sequenceU.map(_.flatten)
有更好的方法吗?
答案 0 :(得分:1)
我们可以使用traverseM
:
引用traverseM
文档(join
是flatten
的Scalaz名称):
traverse的一个版本,其中后续的monadic连接应用于内部结果。
sequence
与traverse(identity)
相同。
因此traverseM(identity)
应该与sequence.map(_.flatten)
类似,但flatten
使用从Option
到List
的隐式转换,而Scalaz只会展平相同的monad类型,因此我们需要明确地将Option
转换为List
:traverseM(_.map(_.toList))
。
使用traverseM
时遇到的问题是我们无法使用Unapply
,就像使用sequenceU
一样。我们需要给编译器一些帮助,并自己指定类型参数(使用类型lambda)。
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))