2017-03-09 26 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