Future[List[Error]/Double]] в Future[[List[Error]\/List[Double]] в Scala

Я играю со 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]]. Как это сделать?


person DennisVDB    schedule 30.08.2016    source источник


Ответы (2)


Эта функция в 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 = \/ (или либо), f = List).

В действии:

scala> import scalaz._, Scalaz._
scala> List(\/-(3), -\/("a")).separate
res1: (List[String], List[Int]) = (List(a),List(3))
person Ven    schedule 30.08.2016
comment
После того, как вы импортировали scalaz.Scalaz._. - person Ende Neu; 30.08.2016
comment
@EndeNeu верно, хе-хе... Это в моем файле sbtrc... Спасибо! - person Ven; 30.08.2016

Строго говоря, вы можете реализовать такую ​​функцию, например, как вы применяете этот список:

-\/(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)
  }
person Zang MingJie    schedule 30.08.2016
comment
Да, тип в вопросе неверный. Cf Цель состоит в том, чтобы сгруппировать левые и правые. что дает подсказку о том, что ищет оператор. - person Ven; 30.08.2016