生成器/块到迭代器/流转换

Daw*_*iak 14 continuations scala yield generator callback

基本上我想转换这个:

def data(block: T => Unit)
Run Code Online (Sandbox Code Playgroud)

到Stream(dataToStream是执行此转换的假设函数):

val dataStream: Stream[T] = dataToStream(data)
Run Code Online (Sandbox Code Playgroud)

我想这个问题可以通过延续来解决:

// let's assume that we don't know how data is implemented
// we just know that it generates integers
def data(block: Int => Unit) { for (i <- 0 to 10) block(i) }

// here we can print all data integers
data { i => println(i) }

// >> but what we really want is to convert data to the stream <<

// very dumb solution is to collect all data into a list
var dataList = List[Int]()
data { i => dataList = i::dataList }
// and make a stream from it
dataList.toStream

// but we want to make a lazy, CPU and memory efficient stream or iterator from data
val dataStream: Stream[Int] = dataToStream(data)
dataStream.foreach { i => println(i) }

// and here a black magic of continuations must be used
// for me this magic is too hard to understand
// Does anybody know how dataToStream function could look like?
Run Code Online (Sandbox Code Playgroud)

谢谢,Dawid

jsu*_*eth 9

编辑:修改示例以显示traversable.view的懒惰

scala> def data(f : Int => Unit) = for(i <- 1 to 10) {    
     |   println("Generating " + i)
     |   f(i)
     | }
data: (f: (Int) => Unit)Unit

scala> def toTraversable[T]( func : (T => Unit) => Unit) = new Traversable[T] {
     |   def foreach[X]( f : T => X) = func(f(_) : Unit)                       
     | }                                                                       
toTraversable: [T](func: ((T) => Unit) => Unit)java.lang.Object with Traversable[T]
Run Code Online (Sandbox Code Playgroud)

toTraversable方法将您的数据函数转换为Traversable集合.它本身并不是什么大事,但你可以把它转换成一个懒惰的TraversableView.这是一个例子:

scala> toTraversable(data).view.take(3).sum
Generating 1
Generating 2
Generating 3
Generating 4
res1: Int = 6
Run Code Online (Sandbox Code Playgroud)

take方法的不幸之处在于它必须超过生成的最后一个值才能正常工作,但它会提前终止.没有".view"调用,上面的代码看起来是一样的.但是,这是一个更引人注目的例子:

scala> toTraversable(data).view.take(2).foreach(println)
Generating 1
1
Generating 2
2
Generating 3
Run Code Online (Sandbox Code Playgroud)

总而言之,我相信你正在寻找的集合是TraversableView,它最容易创建一个Traversable视图,然后在其上调用"view".如果你真的想要Stream类型,这里有一个在2.8.0.final中工作的方法,并且会生成一个没有线程的"Stream":

scala> def dataToStream( data : (Int => Unit) => Unit) = {
     |   val x = new Traversable[Int] {                     
     |     def foreach[U](f : Int => U) = {                 
     |        data( f(_) : Unit)                            
     |     }
     |   }
     |   x.view.toList.toStream                             
     | }
dataToStream: (data: ((Int) => Unit) => Unit)scala.collection.immutable.Stream[Int]

scala> dataToStream(data)
res8: scala.collection.immutable.Stream[Int] = Stream(0, ?)
Run Code Online (Sandbox Code Playgroud)

这种方法的不幸之处在于它会在制作流之前遍历整个遍历.这也意味着需要在内存中缓冲所有值.唯一的选择是诉诸线程.

暂且不说:这是偏向于Traversables作为scalax.io.File方法的直接回报的动机:"行""字符"和"字节".


huy*_*hjl 2

我仍然需要自己弄清楚如何做到这一点。我怀疑答案就在这里:

编辑:删除了显示如何解决不同问题的代码。

Edit2:使用最初发布的代码http://gist.github.com/580157 http://gist.github.com/574873,您可以执行以下操作:

object Main {
  import Generator._

  def data = generator[Int] { yld =>
    for (i <- suspendable(List.range(0, 11))) yld(i)
  }

  def main(args: Array[String]) {
    for( i <- data.toStream ) println(i)
  }
}
Run Code Online (Sandbox Code Playgroud)

data不采用块代码,但我认为这很好,因为通过延续,块可以由调用者处理。Generator的代码可以在github上的gist中看到。