Решить Seq [Будущее [Либо [A, Seq [B]]]] - Scala Cats - PullRequest
1 голос
/ 06 мая 2019

Я сталкиваюсь с проблемой, когда пытаюсь разрешить результат метода.Более конкретно, у меня есть:

def methodA(): Future[Either[Error, Seq[A]]]

, и в какой-то момент я хочу вызвать этот метод для каждого элемента списка и объединить результат.Примерно так:

val tes: Seq[Future[Either[Error, Seq[A]]]] = relevantRounds.map(round =>
            methodA()
          )

Знаете ли вы, как я могу разрешить Seq[Future[Either[Error, Seq[A]]]]?

Итак, что я, наконец, хочу, это Future[Either[Error, Seq[A]]] с последовательностью, которая содержит результат целогосписок.

Ответы [ 2 ]

2 голосов
/ 06 мая 2019

Попробуйте .flatTraverse (упаковка Future[Either[Error, Vector[A]]] с Nested[Future, Either[Error, ?], Vector[A]]).

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import cats.data.Nested
import cats.syntax.traverse._
import cats.syntax.functor._
import cats.instances.vector._
import cats.instances.future._
import cats.instances.either._

trait A
def methodA(): Future[Either[Error, Seq[A]]] = ???

trait Round
val relevantRounds: Seq[Round] = ???

val tes: Future[Either[Error, Seq[A]]] = 
  relevantRounds.toVector
    .flatTraverse(round => 
      Nested(methodA()).map(_.toVector)
    ).value

Vector используется вместо Seq по причине .

2 голосов
/ 06 мая 2019

Вы, вероятно, ищете

  def combine[A](s: Seq[Future[Either[Error, Seq[A]]]]) = {
    Future.sequence(s)
      .map(x => {
        x.foldRight(Right(Seq()): Either[Error, Seq[A]]) {
          (e, acc) => for (xs <- acc.right; x <- e.right) yield x ++ xs
        }
      }
      )
  }

Если вы хотите, чтобы функции выполнялись только в случае успешного выполнения предыдущего, используйте это

  def combine[A](s: Seq[() => Future[Either[Error, Seq[A]]]]): Future[Either[Error, Seq[A]]] =
    combine(Seq(), s)

  def combine[A](acc: Seq[A], s: Seq[() => Future[Either[Error, Seq[A]]]]): Future[Either[Error, Seq[A]]] = s match {
    case x +: Nil =>
      val v = x.apply()
      v.andThen {
        case Success(Right(r)) => Success(Right(acc ++ r))
        case Success(Left(l)) => Success(Left(l))
        case Failure(f) => Failure(f)
      }
    case x +: xs =>
      val v = x.apply()
      v.andThen {
        case Success(Right(r)) => combine(acc ++ r, xs)
        case Success(Left(l)) => Success(Left(l))
        case Failure(f) => Failure(f)
      }
  }
...