2016-06-24 6 views
5

Future[Either[A, B]]BからFuture[C]を提供する関数があります。未来[B =>未来[C])関数を使用して[A、B]〜未来[A、C]のいずれかです。

Future[Either[A, B]]Future[Either[A, C]]に変換する必要があります。

Future[Either[A, C]]を入手する直接の方法はありますが、Future[Either[A, Future[C]]]はありませんか?

私のようなものを考えている:

val eventuallyInitialValue: Future[Either[A, B]] = ??? 
val result: Future[Either[A, C]] = for { 
    e: Either[A, B] <- initialValue 
    c: C <- service.getValue(e.right) 
} yield e.right.map(_ => c) 

service.getValue(e.right)がコンパイルされませんので、それはちょうど擬似コードです。それを行う正しい方法は何でしょうか?

答えて

7

これは私が思い付いたものです:基本的にあなたが未来をflatMapことができ、それはあなたが未来とマップを適用することができそうですならば、それは左だ場合だけ、成功を返す

type B = Int 
type A = String 
type C = Long 
val eitherF: Future[Either[A, B]] = ??? 
def f(b: B): Future[C] = ??? 

val mapped: Future[Either[A, C]] = eitherF.flatMap { 
    case Left(a) => 
    Future.successful(Left(a)) 
    case Right(b) => 
    f(b).map(Right(_)) 
} 

それにはRightです。

3

B => Future[C]関数をEither[E, B] => Future[Either[E, C]]関数に持ち上げると、元の将来はflatMapになります。

eventuallyInitialValue.flatMap { 
    case Left(e) => Future.successful(Left(e)) 
    case Right(r) => bToFC(r).map(Right.apply _) 
} 
+0

感謝を。 bToFC(r).map(右(_)) –

+0

@Alban:うん、 – Daenyth

+0

で編集しました。「Future.apply」ではなく「Future.successful」を使用すると、スレッドプール上に 'Left(e)'を作成します。 –

6

ここにスカラズの解決策があります。それはどちらかのscalazバージョンを使用することに注意してください。

class A 
class B 
class C 

val initial: Future[A \/ B] = (new B).right.point[Future] 
val f: B => Future[C] = _ => (new C).point[Future] 

val result: Future[A \/ C] = (for { 
           e <- EitherT(initial) 
           res <- EitherT(f(e).map(_.right)) 
           } yield res).run 

それは@Endeノイが何をしたか、基本的には同じですが、マッチングやリラップはモナド変換子の中に隠されています。

+0

'initial.flatMap(_。fold(identity.(Right.apply _)compose f)'? – Daenyth

+0

これは私のためにはコンパイルされません。それは興味深く見えますし、答えとして投稿するべきかもしれません。 –

+0

あなたはそうです、型が間違っています; 'f'の結果に' Right'をマップする必要があります – Daenyth

1

猫は現在OptionTと機能B => F[C]を取るXorTにメソッドsemiflatMapを追加するan open pull requestを持っています。

我々はscalaz.EitherTのために同様の機能を作成することができます。

import scalaz._, Scalaz._ 

def semiFlatMap[F[_]: Monad, A, B, C](e: EitherT[F, A, B])(f: B => F[C]): EitherT[F, A, C] = 
    e.flatMap(f andThen EitherT.right[F, A, C]) 

次にあなたができる:

import scala.concurrent.Future 
import scala.concurrent.ExecutionContext.Implicits.global 

val futureEither: Future[Either[String, Int]] = Future.successful(Right(1)) 
val f: Int => Future[Long] = i => Future.successful(i + 1L) 

val appliedF: EitherT[Future,String,Long] = 
    semiFlatMap(EitherT.fromEither(futureEither))(f) 

val futureEither2: Future[Either[String, Long]] = appliedF.run.map(_.toEither) 
関連する問題