为什么流折叠操作抛出内存异常?

yur*_*ura 6 scala scala-collections

我有以下简单的代码

 def fib(i:Long,j:Long):Stream[Long] = i #:: fib(j, i+j)
 (0l /: fib(1,1).take(10000000)) (_+_)
Run Code Online (Sandbox Code Playgroud)

它会抛出OutOfMemmoryError异常.我无法理解为什么,因为我认为所有部分都使用常量内存,即惰性评估流和foldLeft ...

这些代码也不起作用

fib(1,1).take(10000000).sum or max, min e.t.c.
Run Code Online (Sandbox Code Playgroud)

如何正确实现无限流并对其进行迭代操作?

Scala版本:2.9.0

另外scala javadoc说,foldLeft操作对于流是memmory安全的

  /** Stream specialization of foldLeft which allows GC to collect
   *  along the way.
   */
  @tailrec
  override final def foldLeft[B](z: B)(op: (B, A) => B): B = {
    if (this.isEmpty) z
    else tail.foldLeft(op(z, head))(op)
  }
Run Code Online (Sandbox Code Playgroud)

编辑:

使用迭代器的实现仍然无用,因为它会抛出$ {domainName}异常

   def fib(i:Long,j:Long): Iterator[Long] = Iterator(i) ++  fib(j, i + j)
Run Code Online (Sandbox Code Playgroud)

如何在Scala中正确定义无限流/迭代器?

EDIT2:我不关心int溢出,我只是想了解如何在scala中创建无限流/迭代器等而没有副作用.

Rex*_*err 6

使用Stream而不是使用的原因Iterator是您不必再次计算系列中的所有小项.但这意味着您需要存储一千万个流节点.不幸的是,它们非常大,因此可能足以溢出默认内存.解决这个问题的唯一现实方法是从更多内存开始(例如scala -J-Xmx2G).(另外,请注意,你将Long大幅溢出;斐波纳契系列增长很快.)

PS我想到的迭代器实现是完全不同的; 你不是用连接的单例构建Iterator的:

def fib(i: Long, j: Long) = Iterator.iterate((i,j)){ case (a,b) => (b,a+b) }.map(_._1)
Run Code Online (Sandbox Code Playgroud)

现在折叠时,可以放弃过去的结果.

  • @Luigi:这并不像你想象的那么明显.在Haskell中,给定代码将在恒定空间中运行,因为只要对该节点进行折叠,列表中的每个节点都将被垃圾收集(如果在折叠之前将列表分配给变量,则仅保留节点,并且然后继续使用列表). (2认同)