假设我有返回的函数,Future[Either[_, _]
我想在失败的情况下应用其中的一些函数,这意味着只将它们应用于左侧.简化的例子是:
def operation1: Future[Either[String, Int]] = Future.successful(Right(5)) def operation2: Future[Either[String, Int]] = Future.successful(Left("error")) def operation2FallBackWork = Future.successful{ println("Doing some revert stuff") Left("Error happened, but reverting was successful") } val res = for { res1 <- EitherT.fromEither(operation1) res2 <- EitherT.fromEither(operation2)//.leftFlatMap(operation2FallBackWork) -???? } yield res1 + res2 Await.result(res.toEither, 5 seconds)
怎么实现呢?
最接近a的leftFlatMap
是MonadError
's handleError
,它具有你期望从被调用的东西中获得的签名leftFlatMap
(尽管请注意,你需要将后备操作更改EitherT
为a并提供常量函数,而不是按原样传递它).您可以EitherT
像这样直接使用实例:
import scala.concurrent.{ Await, Future } import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.duration._ import scalaz._, Scalaz._ def operation1: Future[Either[String, Int]] = Future.successful(Right(5)) def operation2: Future[Either[String, Int]] = Future.successful(Left("error")) def operation2FallBack: EitherT[Future, String, Int] = EitherT( Future.successful { println("Doing some revert stuff") "Error happened, but reverting was successful".left } ) val E: MonadError[({ type L[x] = EitherT[Future, String, x] })#L, String] = implicitly val res = for { a <- EitherT.fromEither(operation1) b <- E.handleError(EitherT.fromEither(operation2))(_ => operation2FallBack) } yield a + b Await.result(res.toEither, 5.seconds)
您还可以使用提供的语法MonadError
使其看起来像EitherT
一个handleError
方法,虽然需要更多的仪式让Scala编译器识别您的操作具有正确的形状:
import scala.concurrent.{ Await, Future } import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.duration._ import scalaz._, Scalaz._ type FE[x] = EitherT[Future, String, x] def operation1: FE[Int] = EitherT(Future.successful(5.right)) def operation2: FE[Int] = EitherT(Future.successful("error".left)) def operation2FallBack: FE[Int] = EitherT( Future.successful { println("Doing some revert stuff") "Error happened, but reverting was successful".left } ) val res = for { a <- operation1 b <- operation2.handleError(_ => operation2FallBack) } yield a + b Await.result(res.toEither, 5.seconds)
我更喜欢第二个版本,但这是一个风格和品味的问题.