2

Future[Either[Future[T1], Future[T2]]] 型のオブジェクトを、Either[Future[T1], Future[T2]] 型のオブジェクトに変換する方法は本当にありますか??

どちらかで動作するflatMapのようなものかもしれません....

私はこのコードを機能させようとしています (ラップされた一連のアクションを実装する同様のコードがありますが、将来は関係ありません。はるかに簡単に機能します)。以下のコードはそれに基づいており、先物を含む状況で機能するように必要な変更が加えられています。

case class WebServResp(msg: String)
case class WebStatus(code: Int)
type InnerActionOutType = Either[Future[Option[WebServResp]], Future[WebStatus]]
type InnerActionSig = Future[Option[WebServResp]] => Either[Future[Option[WebServResp]], Future[WebStatus]]

val chainOfActions: InnerActionSig = Seq(
  {prevRespOptFut => 
    println("in action 1: " + prevRespOptFut)
    //dont care about prev result
    Left(Future.successful(Some(WebServResp("result from 1"))))
  },
  {prevRespOptFut => 
    println("in action 2: " + prevFutopt)
    prevRespOptFut.map {prevRespOpt =>
      //i know prevResp contains instance of WebServResp. so i skip the opt-matching
      val prevWebServResp = prevRespOpt.get
      Left(Some(prevWebServResp.msg + " & " + " additional result from 2"))
    }

    //But the outcome of the map above is: Future[Left(...)]
    //What I want is Left(Future[...])
  }
)

type WrappedActionSig = InnerActionOutType => InnerActionOutType 
val wrappedChainOfActions = chainOfActions.map {innerAction => 
  val wrappedAction: WrappedActionSig = {respFromPrevWrappedAction =>
    respFromPrevWrappedAction match {
      case Left(wsRespOptFut) => {        
        innerAction(wsRespOptFut)       
      }
      case Right(wsStatusFut) => {
        respFromPrevWrappedAction
      }
    }
  }
  wrappedAction
}

wrappedChainOfActions.fold(identity[WrappedActionIOType] _)  ((l, r) => l andThen r).apply(Left(None))

更新 更新 更新

以下のディディエからのコメントに基づいて(Scala Future、どちらでも動作するflatMap)...動作するコードは次のとおりです。

//API
case class WebRespString(str: String)
case class WebStatus(code: Int, str: String)
type InnerActionOutType = Either[Future[Option[WebRespString]], Future[WebStatus]]
type InnerActionSig = Future[Option[WebRespString]] => InnerActionOutType

type WrappedActionSig = InnerActionOutType => InnerActionOutType
def executeChainOfActions(chainOfActions: Seq[InnerActionSig]): Future[WebStatus] = {
  val wrappedChainOfActions : Seq[WrappedActionSig] = chainOfActions.map {innerAction => 
    val wrappedAction: WrappedActionSig = {respFromPrevWrappedAction =>
      respFromPrevWrappedAction match {
        case Left(wsRespOptFut) => {        
          innerAction(wsRespOptFut)       }
        case Right(wsStatusFut) => {
          respFromPrevWrappedAction
        }
      }
    }
    wrappedAction
  }  

  val finalResultPossibilities = wrappedChainOfActions.fold(identity[InnerActionOutType] _)  ((l, r) => l andThen r).apply(Left(Future.successful(None)))
  finalResultPossibilities match {
    case Left(webRespStringOptFut) => webRespStringOptFut.map {webRespStringOpt => WebStatus(200, webRespStringOpt.get.str)}
    case Right(webStatusFut) => webStatusFut
  }  
}

//API-USER

executeChainOfActions(Seq(
  {prevRespOptFut => 
    println("in action 1: " + prevRespOptFut)
    //dont care about prev result
    Left(Future.successful(Some(WebRespString("result from 1"))))
  },
  {prevRespOptFut => 
    println("in action 2: " + prevRespOptFut)
    Left(prevRespOptFut.map {prevRespOpt => 
      val prevWebRespString = prevRespOpt.get
      Some(WebRespString(prevWebRespString.str + " & " + " additional result from 2"))
    })
  }  
)).map {webStatus =>
  println(webStatus.code + ":" + webStatus.str)
}

executeChainOfActions(Seq(
  {prevRespOptFut => 
    println("in action 1: " + prevRespOptFut)
    //Let's short-circuit here
    Right(Future.successful(WebStatus(404, "resource non-existent")))
  },
  {prevRespOptFut => 
    println("in action 2: " + prevRespOptFut)
    Left(prevRespOptFut.map {prevRespOpt => 
      val prevWebRespString = prevRespOpt.get
      Some(WebRespString(prevWebRespString.str + " & " + " additional result from 2"))
    })
  }  
)).map {webStatus =>
  println(webStatus.code + ":" + webStatus.str)
}

ありがとう、ラカ

4

2 に答える 2

7

このタイプFuture[Either[Future[T1], Future[T2]]]は、後で (それは将来) ときどきどちらかを取得することを意味するため、その時点で、計算がどちらに進むか、さらに後で T1 または T2 のどちらを取得するかがわかります。

したがって、どのブランチが選択されるか (LeftまたはRight) は後でわかります。型Either[Future[T1], Future[T2]とは、その知識を現在持っていることを意味します (結果がどうなるかはわかりませんが、それがどのような型になるかはすでにわかっています)。未来から抜け出す唯一の方法は、待つことです。

ここには魔法はありません。後で今になる唯一の方法は待つことです。これはresult未来で行われ、推奨されません。`

代わりにできることは、完了していない限り、どの分岐が行われたかを知ることにあまり関心がないので、それでFuture[Either[T1, T2]]十分であると言うことです。それは簡単だ。あなたがどちらかを持っていて、実際の結果を待つのではなく、見ていないとしましょう:

def asFuture[T1, T2](
    either: Either[Future[T1], Future[T2]])(
    implicit ec: ExecutionContext)
 : Future[Either[T1, T2] =  either match {
   case Left(ft1) => ft1 map {t1 => Left(t1)}
   case Right(ft2) => ft2 map {t2 => Right(t2)}
}

あなたはEitherまだ持っていませんが、それには未来があるので、flatMapだけです

f.flatMap(asFuture) : Future[Either[T1, T2]]

(ExecutionContext暗黙的に利用可能である必要があります)

于 2014-11-09T08:10:06.467 に答える
1

Eitherの「失敗」のケースがFuture?である必要はないようです。その場合、scalaz を使用できます (どちらかの「成功」の場合は右側にあることに注意してください):

import scalaz._
import scalaz.Scalaz._

def futureEitherFutureToFuture[A, B](f: Future[Either[A, Future[B]]])(
  implicit ec: ExecutionContext): Future[Either[A, B]] =
  f.flatMap(_.sequence)

ただし、常にFutureAPI の外側に保持flatMapし、クライアントではなくコードに保持するのがおそらく最善です。(ここでは の一部ですfoldLeftM):

case class WebServResp(msg: String)
case class WebStatus(code: Int)
type OWSR = Option[WebServResp]
type InnerActionOutType = Future[Either[WebStatus, OWSR]]
type InnerActionSig = OWSR => InnerActionOutType

def executeChain(chain: List[InnerActionSig]): InnerActionOutType = 
  chain.foldLeftM(None: OWSR) {
    (prevResp, action) => action(prevResp)
  }

//if you want that same API
def executeChainOfActions(chainOfActions: Seq[InnerActionSig]) =
  executeChain(chainOfActions.toList).map {
    case Left(webStatus) => webStatus
    case Right(webRespStringOpt) => WebStatus(200, webRespStringOpt.get.str)
  }

(「回復」タイプのアクションが必要な場合は、本当に である必要がありOWSRますが、Eitherそれでも を作成InnerActionOutTypeする必要があり、必要に応じてアクションでまたはFuture[Either[...]]を使用できます。「エラー回復」タイプのアクションの例がある場合、その例をここに置くことができます).traverse.sequence

于 2014-11-09T12:31:39.950 に答える