【问题标题】:Scala stream computation throws StackOverflowErrorScala 流计算抛出 StackOverflowError
【发布时间】:2016-03-30 22:37:03
【问题描述】:

为什么这段代码sn-p执行会导致StackOverflowError

lazy val primes: Stream[Int] = 2 #:: Stream.from(3, 2) filter { pc =>
  primes.takeWhile(x => x * x <= pc) forall (p => pc % p != 0)
}
primes.take(5).last

虽然这段代码 sn-p 工作得很好(请参阅filter 之前的点):

lazy val primes: Stream[Int] = 2 #:: Stream.from(3, 2).filter { pc =>
  primes.takeWhile(x => x * x <= pc) forall (p => pc % p != 0)
}
primes.take(5).last

【问题讨论】:

    标签: scala stream stack-overflow


    【解决方案1】:

    括号将使此处的执行顺序更加明显。 primes 的以下两个定义相当于它们在 OP 中的对应物。

    // fails with stack overflow
    lazy val primes: Stream[Int] = (2 #:: Stream.from(3, 2)) filter { pc =>
      primes.takeWhile(x => x * x <= pc) forall (p => pc % p != 0)
    }
    
    // succeeds
    lazy val primes: Stream[Int] = 2 #:: (Stream.from(3, 2).filter { pc =>
      primes.takeWhile(x => x * x <= pc) forall (p => pc % p != 0)
    })
    

    好的,那么第一个有什么问题?它首先通过创建流(2 #:: Stream.from(3, 2)) 来定义,然后对其进行过滤。让我们尝试访问第一个元素:

    primes.head
    

    这实际上也会产生堆栈溢出。以下是发生的事情:

    1. head 尝试访问 primes 的第一个元素。
    2. 必须根据 filter 谓词检查第一个元素 2
    3. 要检查谓词,我们必须递归访问primes
    4. 我们尝试获取primes 的第一个元素,它必须在2 上运行filter 谓词。
    5. 重复第 3 步。

    ...导致堆栈溢出。

    第二个例子没有遇到这个问题,因为Stream2)的头部没有被过滤,所以在这一步没有递归检查2是否真的存在.也就是说,在第二个例子中,很明显2Streamhead。在第一个示例中,Stream 中的 head 必须通过检查 filter 来计算,但为此在无限递归循环中引用自身。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-10-28
      • 2012-04-29
      • 1970-01-01
      • 2013-01-12
      • 2018-07-10
      • 2023-03-10
      • 1970-01-01
      • 2017-09-10
      相关资源
      最近更新 更多