2017-01-15 4 views
3

と答えましょう。私はFuture[Either[_, _]を返す関数を持っていて、これらの関数のいくつかを失敗の場合に適用したいとしましょう。簡略化された例は次のとおりです。残りのflatMapを

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) 

これを実現する方法は?

答えて

10

leftFlatMapに最も近いものは、あなたがEitherTにフォールバック操作を変更し、一定の機能を提供する必要がありますleftFlatMap(ただし、ノートと呼ばれるものから期待正確に署名を持っているMonadErrorさんhandleError、ありますそのまま渡すのではなく)。あなたは直接このよう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) 

それがScalaのコンパイラを取得するには、もう少し式典がかかりますが、あなたはまた、EitherThandleErrorメソッドを持っているようにそれが見えるようにMonadErrorが提供する構文を使用することができます

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) 

私はこの2番目のバージョンが好きですが、それはスタイルと趣味の問題です。