Кошки, уменьшая Seq of EitherT - PullRequest
       76

Кошки, уменьшая Seq of EitherT

1 голос
/ 21 октября 2019

Я работаю над проектом, в котором обнаружил кошек типа EitherT. В одной из моих задач я хотел бы уменьшить Seq от производителя EitherT[Future, L, R] до EitherT[Future, L, Seq[R]], когда все они правильны . И чтобы прервать сокращение и вернуть неудачное LeftT[Future, L, Seq[R]] в противном случае.

У меня есть успешное сокращение для счастливого пути с помощью следующего кода:

type Producer = () => EitherT[Future, L, Seq[R]] // where L and R are known types.
private def execute(producers:Seq[Producer]):EitherT[Future, L, Seq[R]] = {
  producers match {
    case last :: Nil =>
      last()
    case current :: nexts =>
      current().flatMap(res => execute(nexts).map(res ++ _))
   } 
}

Но я не могу найти чистый путьобрабатывать LefT. Есть ли у вас какие-либо советы о том, как обращаться с левым регистром для моего сокращения?

Спасибо

Редактировать : потому что это может быть недостаточно ясно.

Мой ввод Seq[Producer] (A Producer дает EitherT, когда он применяется). Я хочу применить и сократить моих производителей до одного EitherT, но я должен прервать процесс, если один производитель потерпит неудачу (возвращает одного EitherT, который содержит Left).

Дано:

  • P1, P2 и P3, три производителя, которые возвращают Right EitherT соответственно Seq(A), Seq(B) и Seq(C, D)
  • Сокращение Seq(P1, P2, P3) вернет EitherT из Right(Seq(A, B, C, D)).

Дано:

  • P1 и P3, два производителя, которые возвращают RightEitherT, соответственно Seq(A) и Seq(C, D)
  • P2 один производитель возвращает `Left (" fail ")

  • Сокращение Seq(P1, P2, P3) вернет EitherT из Left("fail").

Редактировать 2: Другая возможность - сбросить производителейрезультат выглядит более или менее одинаково (а накопление пропущенных производителей менее чисто):

var history = Seq.empty[]
val empty = //..
producers.foldLeft(empty) {
  case (left, producer) =>
    history :+ producer // May be in history while failed
    producer().flatMap(i => left.map(_ + i))
}

Ответы [ 2 ]

1 голос
/ 21 октября 2019

Использовать .sequence

  import cats.implicits._

  val success = List(
    EitherT.right[Int](Option("1")),
    EitherT.right[Int](Option("2")))

  println(success.sequence) // EitherT(Some(Right(List(1, 2))))

  val error = success :+ EitherT.left[String](Option(3))

  println(error.sequence) // EitherT(Some(Left(1)))
0 голосов
/ 21 октября 2019

Вы можете использовать sequence метод из import cats.syntax.traverse._

import cats.data.EitherT
import cats.instances.future._
import cats.instances.list._
import cats.syntax.traverse._

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scala.util.Random

object CatsTravers extends App {

  def right(int: Int) =
    EitherT[Future, String, Int](Future(Right(int)))

  def left(str: String): EitherT[Future, String, Int] =
    EitherT[Future, String, Int](Future(Left(str)))

  def producer() = {
    val int = Random.nextInt()
    println(s"Calling producer with result $int")
    if(int > 0) right(int) else left("Negative")
  }

  val produced: List[EitherT[Future, String, Int]] = (0 until 3).map { i =>
    producer()
  }.toList

  Thread.sleep(1000)

  println(produced.sequence)
}

Выходы

Calling producer with result -41083676
Calling producer with result 750919792
Calling producer with result 1778645417
EitherT(Future(Success(Left(Negative))))

РЕДАКТИРОВАТЬ:

Перед вызовом sequence, вы должнынакапливать результаты метода producer, например, сохраняя его в отдельном val, как это сделано в коде выше

...