如何转换List [ValidationNel [A,Option [B]]]

时间:2015-12-22 21:02:47

标签: scala scalaz

我需要一个组合器将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)

有更好的方法吗?

1 个答案:

答案 0 :(得分:1)

我们可以使用traverseM

  • 引用traverseM文档(joinflatten的Scalaz名称):

      

    traverse的一个版本,其中后续的monadic连接应用于内部结果。

  • sequencetraverse(identity)相同。

因此traverseM(identity)应该与sequence.map(_.flatten)类似,但flatten使用从OptionList的隐式转换,而Scalaz只会展平相同的monad类型,因此我们需要明确地将Option转换为ListtraverseM(_.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))