在斯卡拉展平Monadic类型的长嵌套

时间:2015-11-11 02:40:05

标签: scala monads

我有一个函数来获取一个给定JobIds的workItemIds,并带有以下签名 -

def getWorkItemIds(jobId: JobId): Future[Seq[WorkItemId]]

我有另一个函数,给定WorkItemId会返回一个workItem。签名 -

def getWorkItem(workItemId: WorkItemId): Future[Option[WorkItem]]

现在我正在尝试编写一个函数,使用这两个函数返回一个给定JobId的WorkItem的seq,就像这样 -

  def getWorkItemsForJob(jobId: JobId): Future[Seq[Future[Option[WorkItem]]]] = {
val workItemIds: Future[Seq[WorkItemId]] = getWorkItemIds(jobId)

   val res = workItemIds.map {
     idSeq => idSeq.map {
       id => getWorkItem(id)
     }
   }
   res
}

问题是返回类型,我不想返回这个怪异的类型,而应该返回像Future[Seq[WorkItem]]这样简单的东西。现在我可以像 -

那样压扁它
  def getWorkItemsForJob(jobId: JobId): Future[Seq[WorkItem]] = {
val workItemIds: Future[Seq[WorkItemId]] = getWorkItemIds(jobId)

  val res = workItemIds.map {
    idSeq => idSeq.flatMap {
      id => getWorkItem(id).get
    }
  }
  res
}

它为我提供了我想要的正确Future[Seq[WorkItem]]类型,但它要求我对未来有所了解,这感觉不正确。我也可以使用await但这将是一个阻塞调用。反正是否有上述类型而没有阻塞?

2 个答案:

答案 0 :(得分:3)

您要找的是Future.traverse

def getWorkItemsForJob(jobId: JobId): Future[Seq[WorkItem]] =
  getWorkItemIds(jobId).flatMap(Future.traverse(_)(getWorkItem).map(_.flatten)) 

.traverse来电从Seq来看getWorkItemIds,并在每个条目上返回Future[Seq]调用getWorkItem的结果,没有内在Future包裹。

靠近末尾的.map(_.flatten)将内部Seq[Option[WorkItem]]展平为Seq[WorkItem]

答案 1 :(得分:3)

您可以通过以下方式执行此操作:

def getWorkItemsForJob(jobId: JobId): Future[Seq[WorkItem]] = 
  for (
    seq <- getWorkItemIds(jobId);
    list <- Future.traverse(seq)(getWorkItem)
  ) yield list.flatten