scalaz, Disjunction.sequence returning a list of l

2019-07-30 12:33发布

问题:

In scalaz 7.2.6, I want to implement sequence on Disjunction, such that if there is one or more lefts, it returns a list of those, instead of taking only the first one (as in 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))

I've implemented it as follows and it works, but it looks ugly. Is there a getRight method (such as in scala Either class, Right[String, Int](3).right.get)? And how to improve this code?

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
    }
}

回答1:

Playing around I've implemented a recursive function for that, but the best option would be to use 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)
  }
}

The first one just collects results and at the end decide what to do with those, the second its basically the same with the exception that the recursive function is much simpler, I didn't think about performance here, I've used :+, if you care use prepend or some other collection.

You may also want to take a look at Validation and ValidationNEL which unlike Disjunction accumulate failures.



标签: scala scalaz