scalaz, Disjunction.sequence 返回左列表 [英] scalaz, Disjunction.sequence returning a list of lefts

查看:42
本文介绍了scalaz, Disjunction.sequence 返回左列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

我已按如下方式实现它并且它有效,但它看起来很难看.是否有 getRight 方法(例如在 scala Either 类中,Right[String, Int](3).right.get)?以及如何改进这段代码?

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

推荐答案

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

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.

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

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

这篇关于scalaz, Disjunction.sequence 返回左列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆