scalaz,Disjunction.sequence 返回左列表

scalaz, Disjunction.sequence returning a list of lefts

在 scalaz 7.2.6 中,我想在 Disjunction 上实现 sequence,这样如果有一个或多个左边,它 returns 一个列表,而不是只取第一个(如 Disjunction.sequenceU):

import scalaz._, Scalaz._

List(1.right, 2.right, 3.right).sequence
res1: \/-(List(1, 2, 3))

List(1.right, "error2".left, "error3".left).sequence
res2: -\/(List(error2, error3))

我已经按如下方式实现了它并且它可以工作,但它看起来很难看。有没有getRight的方法(比如scala中的Eitherclass,Right[String, Int](3).right.get)?如何改进这段代码?

implicit class RichSequence[L, R](val l: List[\/[L, R]]) {
  def getLeft(v: \/[L, R]):L = v match { case -\/(x) => x }
  def getRight(v: \/[L, R]):R = v match { case \/-(x) => x }

  def sequence: \/[List[L], List[R]] =
    if (l.forall(_.isRight)) {
      l.map(e => getRight(e)).right
    } else {
      l.filter(_.isLeft).map(e => getLeft(e)).left
    }
}

我已经为此实现了一个递归函数,但最好的选择是使用 separate:

implicit class RichSequence[L, R](val l: List[\/[L, R]]) {
  def sequence: \/[List[L], List[R]] = {
    def seqLoop(left: List[L], right: List[R], list: List[\/[L, R]]): \/[List[L], List[R]] =
      list match {
        case (h :: t) =>
          h match {
            case -\/(e) => seqLoop(left :+ e, right, t)
            case \/-(s) => seqLoop(left, right :+ s, t)
          }
        case Nil =>
          if(left.isEmpty) \/-(right)
          else -\/(left)
    }
    seqLoop(List(), List(), l)
  }


  def sequenceSeparate: \/[List[L], List[R]] = {
    val (left, right) = l.separate[\/[L, R], L, R]
    if(left.isEmpty) \/-(right)
    else -\/(left)
  }
}

第一个只是收集结果,最后决定如何处理这些结果,第二个基本相同,只是递归函数要简单得多,我在这里没有考虑性能,我'我已经使用了 :+,如果您愿意,请使用 prepend 或其他一些集合。

您可能还想看看 ValidationValidationNEL,它们与 Disjunction 累积失败不同。