6

I'm playing around with Scala(z) to learn functionnal programming.

I have a value of type Future[List[Error \/ Double]] and want to transform it to something with the type Future[[List[Error] \/ List[Double]].

The goal is to group the lefts and rights.

I currently have the following:

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

However, I get an error on the :: which is due to the fact that my accumulator is not a list (from the outside) \/[List[Error], List[Double]]. How should it be done?

DennisVDB
  • 1,347
  • 1
  • 14
  • 30

2 Answers2

5

This function in Haskell would be partitionEithers: [Either a b] -> ([a], [b]).

(You don't actually want Either [a] [b], that wouldn't really make sense. I'm guessing you want this function instead because of the text in your description...)

Scalaz doesn't have it as-is. However, it has a more general 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])

Which is basically Bifoldable g, MonadPlus f => f (g a b) -> (f a), (f b). Specifically: [Either a b] -> ([a], [b]). You can simply call it on your list (where g = \/ (or Either), f = List).

In action:

scala> import scalaz._, Scalaz._
scala> List(\/-(3), -\/("a")).separate
res1: (List[String], List[Int]) = (List(a),List(3))
Ven
  • 19,015
  • 2
  • 41
  • 61
0

Strictly, you can implement such function, for example, how do you apply this list:

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

Assume the input list is all left or all right, you can peek the first one , and decide how to deal the remains:

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

Assume you want to group lefts and rights, a single fold which returns (List[L], List[R]) works perfectly:

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)
  }
Zang MingJie
  • 5,164
  • 1
  • 14
  • 27
  • Yes, the type in the question is incorrect. Cf "The goal is to group the lefts and rights." which gives the hint as to what the op's looking for. – Ven Aug 30 '16 at 12:37