简体   繁体   中英

Convert EitherT[Future, A, B] to Option[B]

I have a method

def getInfoFromService(reqParams: Map[String, String]): Future[Either[CustomException, A]] 

and I have another function

import cats.implicits._
def processInfoAndModelResponse(input: Future[Either[CustomException, A]]): Option[A] = {
    for {
         either <- input
         resultA <- either
     } yield resultA.some
}

So basically, I am trying to convert Future[Either[CustomException, A]]) to Option[A] . The resultA <- either in above code would not work as map is not happy with type.

What you try to do is basically something like

def convert[A](future: Future[Either[CustomException, A]]): Option[A] =
  Try(Await.result(future, timeout)).toEither.flatten.toOption

This:

  • looses information about error, which prevents any debugging (though you could log after .flatten )
  • blocks async operation which kills any benefit of using Future in the first place

Monads do not work like that. Basically you can handle several monadic calculations with for for the same monad, but Future and Either are different monads.

Try

import scala.concurrent.{Await, Future}
import scala.concurrent.duration._

def processInfoAndModelResponse(input: Future[Either[CustomException, A]]): Option[A] = {
  Await.result(input, 1.minute).toOption
}

@MateuszKubuszok 's answer is different in that it doesn't throw.

You can't sensibly convert a Future[Either[CustomException, A]] to Option[A] , as you don't know what the result will be until the Future has completed.

Future[Either[CustomException, A]] might just bet kept that way, or put in IO as IO[Either[CustomException, A]] . If you don't care about CustomException , you can also capture it Future (or IO ) error handling mechanisms, or just discard it entirely.

Some options:

absorb the CustomException in Future's error handling:

val fa: Future[A] = fut.transform(_.map(_.toTry))

ignore the CustomException an make the Future return with None

val fa: Future[Option[A]] = fut.map(_.toOption)

if you really want to block a thread and wait for the result,

Await.result(input, Duration.Inf).toOption

but all the caveats of awaiting apply. See the documentaion , reproduced here:

WARNING: It is strongly discouraged to supply lengthy timeouts since the progress of the calling thread will be suspended—blocked—until either the Awaitable has a result or the timeout expires.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM