2017-03-09 50 views
0

我如何「修復」這種反應,我想未來的[選項[F4]如何刪除期貨期權未來的許多層中

val f4Response: Future[Option[Future[Option[Future[F4]]]]] = 
    for { 
     f1Opt <- api.getF1() // Future[Option[F1]] 
     f2Opt <- if (f1Opt.isDefined) api.getF2(f1Opt.get.id) else Future.successful(None) // getF2 is Future[Option[F3]] 
    } yield { 
     for { 
      f1 <- f1Opt 
      f2 <- f2Opt 
     } yield { 
      for { 
       f3Opt <- api.getF3(f1.id, f2.id) // Future[Option[F3]] 
      } yield { 
       for { 
        f3 <- f3Opt 
       } yield { 
        api.insertF(f1, f2, f3) // Future[Option[F4]] 
       } 
      } 
     } 
    } 

更新

我響應嘗試使用scalaz但我得到一個錯誤:

val result: Future[Option[f4]] = (
      for { 
       f1 <- OptionT(api.getF1(..)) 
       f2 <- OptionT(api.getF2(..)) 
       f3 <- OptionT(api.getF3(f1.id, f2.id) 
      } yield api.getF4(f1, f2, f3) 
     ).run 

錯誤是:

[error] found : scala.concurrent.Future[Option[scala.concurrent.Future[F4]]] 
[error] required: scala.concurrent.Future[Option[F4]] 

另外,我不能在線路接入f1.id和f2.id

f3 <- OptionT(api.getF3(f1.id, f2.id) 

回答

1

這是完美適合catsOptionT monad變壓器。

你需要一些貓進口:

import cats.data.OptionT 
import cats.instances.future._ 

讓我們說這是你的數據結構(嘲笑):

case class F1(id: Int) 
case class F2(id: Int) 
case class F3(id: Int) 
trait F4 

object api { 
    def getF1(): Future[Option[F1]] = ??? 
    def getF2(f1: Int): Future[Option[F2]] = ??? 
    def getF3(f1: Int, f2: Int): Future[Option[F3]] = ??? 
    def insertF(f1: Int, f2: Int, f3: Int): Future[Option[F4]] = ??? 
} 

那麼你可以做:

val resultT: OptionT[Future, F4] = for { 
    f1 <- OptionT(api.getF1()) 
    f2 <- OptionT(api.getF2(f1.id)) 
    f3 <- OptionT(api.getF3(f1.id, f2.id)) 
    f4 <- OptionT(api.insertF(f1.id, f2.id, f3.id)) 
} yield f4 

val result: Future[Option[F4]] = resultT.value 

或者你可以直接換你的方法與OptionT

type FutOpt[T] = OptionT[Future, T] 

def getF1(): FutOpt[F1] = OptionT { ??? } 
def getF2(f1: Int): FutOpt[F2] = OptionT { ??? } 
def getF3(f1: Int, f2: Int): FutOpt[F3] = OptionT { ??? } 
def insertF(f1: Int, f2: Int, f3: Int): FutOpt[F4] = OptionT { ??? } 

val resultT: FutOpt[F4] = for { 
    f1 <- api.getF1() 
    f2 <- api.getF2(f1.id) 
    f3 <- api.getF3(f1.id, f2.id) 
    f4 <- api.insertF(f1.id, f2.id, f3.id) 
} yield f4 

val result: Future[Option[F4]] = resultT.value 

您還可以使用scalazOptionT保持完全相同的語法(除了.value - >.run)僅通過改變進口。

import scalaz._ 
import Scalaz._ 

def insertF(f1: Int, f2: Int, f3: Int): Future[F4]代替Future[Option[F4]]你可以重寫換理解(使用scalaz)爲:

val resultT: OptionT[Future, F4] = for { 
    f1 <- OptionT(api.getF1()) 
    f2 <- OptionT(api.getF2(f1.id)) 
    f3 <- OptionT(api.getF3(f1.id, f2.id)) 
    f4 <- api.insertF(f1.id, f2.id, f3.id).liftM[OptionT] 
} yield f4 

val result: Future[Option[F4]] = resultT.run 
+0

不Catz公司OptionT行爲相同scalaz OptionT? – Blankman

+0

如果我嘗試用scalaz做這件事,我必須發出1)我不能做f1.id,f2.id來獲得f3 2)它返回Future [Option [Future [F4]]我將添加我我現在的問題幾乎是 – Blankman

+1

,你只需要改變一些語法(例如'value' - >'run'),我將提供一個'scalaz'的例子...... –

0
val f4Response: Future[Option[Int]] = api.getF1() flatMap { 
    case Some(f1) => { 
    api.getF2(f1).flatMap { 
     case Some(f2) => { 
     api.getF3(f1.id, f2.id).flatMap { 
      case Some(f3) => bar(f1, f2, f3) 
     } 
     } 
    } 
    } 
} 

for yield也許是必要爲這種情況patter match也許是更好的,沒有直接Option.get(它可能會失敗),它更安全的pattern match