Reputation: 4004
I have two methods and both returns for Future[Either[String, T]] and want to chain them together to get the job done. I am using Scala 2.12 Either is right biased now.
For example,
If the function not return Future and Either combination, I can simply do like following with for comprehension.
def convert(a, b) = ???
def callA(): Future[A] = ???
def callB(a: A): Future[B] = ???
def chain: Future[C] = for {
a <- callA
b <- callB(a)
} yield convert(a, b)
but now I want to capture the error using Either with following syntax, and propagate to the final result. what's the best way to achieve that? Also should callB or callB1 used?
def convert(a, b): Future[Either[String, C]] = ???
def callA(): Future[Either[String, A]] = ???
def callB(a: A): Future[Either[String, B]] = ??? or
def callB1(eithera: Either[String, A]): Future[Either[String, B]] = ???
I know using cats transform monad could simplify this. Welcome to give me solution for both using standard lib and cats.
Upvotes: 4
Views: 1055
Reputation: 18434
As the comments have mentioned, this is something cats and scalaz can handle. But I can also understand the desire to not introduce another dependency or complication for a pretty small piece of logic. Here's what you could do if you want to implement it yourself:
implicit class FutureEither[A](val wrapped: Future[Either[String, A]])(implicit ec: ExecutionContext) {
def map[B](f: A => B): FutureEither[B] = wrapped.map(_.map(f))
def flatMap[B](f: A => FutureEither[B]): FutureEither[B] = wrapped.flatMap {
case Left(s) => Future(Left(s))
case Right(a) => f(a).wrapped
}
}
Implementing map
and flatMap
with appropriate types enables the exact same style of for-comprehension:
def convert(a: A, b: B): C = ???
def callA(): FutureEither[A] = ???
def callB(a: A): FutureEither[B] = ???
def chain: FutureEither[C] = for {
a <- callA()
b <- callB(a)
} yield convert(a, b)
Upvotes: 6