I am working on a project where I discovered the cats's EitherT type. In one of my tasks I would like to reduce a Seq of of producer of EitherT[Future, L, R] to an EitherT[Future, L, Seq[R]] when they are all right. And to abort the reduction and return the failed LeftT[Future, L, Seq[R]] otherwise.
I have a successful reduction for the happy path with the following code:
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 ++ _))
}
}
But I cannot find a clean way to handle a LefT. Do you have any tips on how to handle the left case on my reduction ?
Thanks
Edit: because it may not be clear enough.
My input is a Seq[Producer] (A Producer give an EitherT when it is applied). I want to apply and reduce my producers to one EitherT but I have to abort the process if one producer fail (returns one EitherT which hold a Left).
Given :
P1,P2andP3, three producers that returns aRightEitherT, respectivelySeq(A),Seq(B)andSeq(C, D)- Reduction of
Seq(P1, P2, P3)will return anEitherTof aRight(Seq(A, B, C, D)).
Given:
P1andP3, two producers that returns aRightEitherT, respectivelySeq(A)andSeq(C, D)P2one producer returning a `Left("fail")Reduction of
Seq(P1, P2, P3)will return anEitherTof aLeft("fail").
Edit 2: Another possibility is to fold the producers bu the result looks more or less the same (and the accumulation of passed producers is less clean) :
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))
}