在 Scala 中展平 Monadic 类型的长嵌套
Flatten long nesting of Monadic types in Scala
我有一个函数可以在给定 JobId 的情况下获取一系列 workItemId,并具有以下签名 -
def getWorkItemIds(jobId: JobId): Future[Seq[WorkItemId]]
我有另一个函数,给定一个 WorkItemId 将 return 一个 workItem。有签名 -
def getWorkItem(workItemId: WorkItemId): Future[Option[WorkItem]]
现在我正在尝试编写一个函数,它使用这两个函数来 return 给定 JobId 的 WorkItem 序列,就像这样 -
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
}
问题是 return 类型,我不想 return 这种可怕的类型,而应该 return 像 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]]
类型,但它要求我对未来做一个 get,这感觉不正确。我也可以使用 await 但这将是一个阻塞调用。有没有办法在不阻塞的情况下展平上述类型?
你要找的是Future.traverse
:
def getWorkItemsForJob(jobId: JobId): Future[Seq[WorkItem]] =
getWorkItemIds(jobId).flatMap(Future.traverse(_)(getWorkItem).map(_.flatten))
.traverse
调用获取 getWorkItemIds
调用的 Seq
和 returns 调用 getWorkItem
结果的 Future[Seq]
每个条目,没有内部 Future
包装。
最后的 .map(_.flatten)
将内部 Seq[Option[WorkItem]]
变平为 Seq[WorkItem]
。
您可以通过以下方式进行:
def getWorkItemsForJob(jobId: JobId): Future[Seq[WorkItem]] =
for (
seq <- getWorkItemIds(jobId);
list <- Future.traverse(seq)(getWorkItem)
) yield list.flatten
我有一个函数可以在给定 JobId 的情况下获取一系列 workItemId,并具有以下签名 -
def getWorkItemIds(jobId: JobId): Future[Seq[WorkItemId]]
我有另一个函数,给定一个 WorkItemId 将 return 一个 workItem。有签名 -
def getWorkItem(workItemId: WorkItemId): Future[Option[WorkItem]]
现在我正在尝试编写一个函数,它使用这两个函数来 return 给定 JobId 的 WorkItem 序列,就像这样 -
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
}
问题是 return 类型,我不想 return 这种可怕的类型,而应该 return 像 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]]
类型,但它要求我对未来做一个 get,这感觉不正确。我也可以使用 await 但这将是一个阻塞调用。有没有办法在不阻塞的情况下展平上述类型?
你要找的是Future.traverse
:
def getWorkItemsForJob(jobId: JobId): Future[Seq[WorkItem]] =
getWorkItemIds(jobId).flatMap(Future.traverse(_)(getWorkItem).map(_.flatten))
.traverse
调用获取 getWorkItemIds
调用的 Seq
和 returns 调用 getWorkItem
结果的 Future[Seq]
每个条目,没有内部 Future
包装。
最后的 .map(_.flatten)
将内部 Seq[Option[WorkItem]]
变平为 Seq[WorkItem]
。
您可以通过以下方式进行:
def getWorkItemsForJob(jobId: JobId): Future[Seq[WorkItem]] =
for (
seq <- getWorkItemIds(jobId);
list <- Future.traverse(seq)(getWorkItem)
) yield list.flatten