具有 Stream 类型的 Scala 递归实现

Scala recursive implementation with Stream type

我已经开始在 Coursera 上学习 Scala,并且有一些关于 squareRootGuess 实现的问题如下

我正在尝试实施标准来过滤 sqrtGuess 定义中的准确猜测,如下所示,但它会给我堆栈溢出错误。

def sqrtGuess(x: Double): Stream[Double] = { 
  def nextGuess(guess: Double): Double = (guess + x / guess)/2

  def isSufficient(guess: Double): Boolean = math.abs(x - guess*guess)/x < 0.001

  def guesses: Stream[Double] = 
    1 #:: guesses.map(nextGuess).filter(isSufficient)

  guesses
}

但是,如果我们在 sqrtGuess 之外定义 isSufficient 并将其应用于 sqrtGuess 流,效果会很好。

def sqrtGuess(x: Double): Stream[Double] = { 
    def nextGuess(guess: Double): Double = (guess + x / guess)/2
    def guesses: Stream[Double] = 
        1 #:: guesses.map(nextGuess)
    guesses
}

def isSufficient(guess: Double, x: Double): Boolean = math.abs(x - guess*guess)/x < 0.001

sqrtGuess(4.2).filter(isSufficient(_, 4.2)).take(10).toList

我想知道 sqrtGuess 的第一个实现发生了什么?我正在尝试使用替代模型来证明它但它似乎没有任何问题。

我假设您使用的是 Scala 2.12,因为 Stream 在 Scala 2.13 中已弃用,弃用消息如下:

Use LazyList (which is fully lazy) instead of Stream (which has a lazy tail only)

我没有真正的证据证明我要说的话,但我可以假设这是正在发生的事情:

在非工作示例中,您尝试根据 x = 4.2guess = 1.0 生成列表。计算出的下一个元素被过滤器丢弃。所以下一个不会添加到流中。因此 guesses 总是无法为流创建新元素,并且我们永远不会在流中达到 10 个元素。无限递归导致栈溢出

为了过滤,您需要先创建流,然后对其进行过滤:

def sqrtGuess1(x: Double): Stream[Double] = {
  def nextGuess(guess: Double): Double = (guess + x / guess)/2

  def isSufficient(guess: Double): Boolean = math.abs(x - guess*guess)/x < 0.001

  def guesses: Stream[Double] =
    1 #:: guesses.map(nextGuess)

  guesses.filter(isSufficient)
}