使用返回Future的函数映射Stream

Mar*_*ijn 14 scala future stream

我有时会发现自己处于一种情况,即我有一些Stream[X],而且function X => Future Y我想要将它结合起来Future[Stream[Y]],而我似乎无法找到办法.例如,我有

val x = (1 until 10).toStream
def toFutureString(value : Integer) = Future(value toString)

val result : Future[Stream[String]] = ???
Run Code Online (Sandbox Code Playgroud)

我试过了

 val result = Future.Traverse(x, toFutureString)
Run Code Online (Sandbox Code Playgroud)

它给出了正确的结果,但似乎在返回Future之前消耗了整个流,这或多或少地击败了purpse

我试过了

val result = x.flatMap(toFutureString)
Run Code Online (Sandbox Code Playgroud)

但那不能编译 type mismatch; found : scala.concurrent.Future[String] required: scala.collection.GenTraversableOnce[?]

val result = x.map(toFutureString)
Run Code Online (Sandbox Code Playgroud)

返回有点奇怪和无用 Stream[Future[String]]

我该怎么做才能解决问题?

编辑:我没有被困在一个Stream,我对同样的操作同样满意Iterator,只要在开始处理头部之前它不会阻止评估所有项目

Edit2:我不是100%确定Future.Traverse构造在返回Future [Stream]之前需要遍历整个流,但我认为确实如此.如果没有,那本身就是一个很好的答案.

编辑3:我也不需要结果顺序,我很好用流或迭代器返回任何顺序.

Tra*_*own 9

你在正确的轨道上traverse,但不幸的是,在这种情况下看起来标准库的定义有点破碎 - 它不需要在返回之前使用流.

Future.traverse是任何适用函子包裹在一个"穿越"类型(见工作的更一般功能的特定版本,这些 文件或我的答案在这里获取更多信息,例如).

Scalaz库提供了更一般的版本,它按预期工作在这种情况下(请注意,我得到了适用函子实例Futurescalaz-contrib;它尚未Scalaz的稳定版本,目前仍在对斯卡拉2.9交叉构建.2,没有这个Future):

import scala.concurrent._
import scalaz._, Scalaz._, scalaz.contrib.std._

import ExecutionContext.Implicits.global

def toFutureString(value: Int) = Future(value.toString)

val result: Future[Stream[String]] = Stream.from(0) traverse toFutureString
Run Code Online (Sandbox Code Playgroud)

这会在无限流中立即返回,因此我们确信它不是首先消耗的.


作为一个脚注:如果您查看源代码,Future.traverse您会看到它foldLeft是以方便的方式实现的,这在流的情况下是方便的,但不是必需的或适当的.