在Scala中将Future[List[Error \/ Double]]转换为Future[[List[Error] \/ List[Double]]。

6

我正在使用Scala(z)进行函数式编程学习。

我有一个类型为Future[List[Error \/ Double]]的值,并希望将其转换为类型为Future[[List[Error] \/ List[Double]]的内容。

目标是将左侧和右侧分组。

我目前有以下内容:

val foo: Future[List[Error] \/ List[Double]] = {
  for {
    results <- resultsF
  } yield
    results.foldLeft(\/[List[Error], List[Double]])({
      case (acc, v) if v.isRight => v :: \/-(acc)
      case (acc, v) if v.isLeft => v :: -\/(acc)
    })
}

然而,我在::处收到一个错误提示,因为我的累加器不是一个列表(从外部来看)\/[List[Error], List[Double]]。应该怎么做?
2个回答

5
这个 Haskell 函数是 partitionEithers: [Either a b] -> ([a], [b])
(你实际上不需要 Either [a] [b],那并没有什么意义。我猜你想要这个函数是因为描述中的文本...)
Scalaz 没有这个函数。但是,它有一个更通用的 separate:
/** Generalized version of Haskell's `partitionEithers` */
def separate[G[_, _], A, B](value: F[G[A, B]])(implicit G: Bifoldable[G]): (F[A], F[B])

基本上是这样的Bifoldable g,MonadPlus f => f(g a b) ->(f a),(f b)。具体来说:[Either a b] ->([a],[b])。您可以在列表上简单地调用它(其中g = \/(或者Either),f = List)。
实际应用:
scala> import scalaz._, Scalaz._
scala> List(\/-(3), -\/("a")).separate
res1: (List[String], List[Int]) = (List(a),List(3))

2
在导入 scalaz.Scalaz._ 之后。 - Ende Neu
@EndeNeu 对,呵呵...那在我的sbtrc文件里...谢谢! - Ven

0

严格来说,你可以实现这样的函数,例如,你如何应用这个列表:

-\/(A) :: \/-(B) :: Nil

假设输入列表全部向左或向右,您可以查看第一个元素,并决定如何处理其余部分:

val foo: Future[List[Error] \/ List[Double]] =
  resultsF.map(resultsF.head match {
    case -\/(_) => { _.left }
    case \/-(_) => { _.right }
  })

假设您想要将左侧和右侧分组,一个返回 (List[L], List[R]) 的单个折叠函数非常完美:
val foo[L,R]: Future[(List[L], List[R])] =
  resultsF.foldr((Nil, Nil)){ (s, v) =>
    case -\/(l) => (l :: s._1, s._2)
    case \/-(r) => (s._1, r :: s._2)
  }

是的,问题中的类型不正确。参见“目标是将左边和右边分组。”这提示了提问者正在寻找什么。 - Ven

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接