Scala error: "forward reference extends over definition of value" when code appears in a function

Scala error: "forward reference extends over definition of value" when code appears in a function

我正在尝试使用 Scala 2.11.7 编译以下代码。

object LucasSeq {
  val fibo: Stream[Int] = 0 #:: 1 #:: fibo.zip(fibo.tail).map { pair =>
    pair._1 + pair._2
  }

  def firstKind(p: Int, q: Int): Stream[Int] = {
    val lucas: Stream[Int] = 0 #:: 1 #:: lucas.zip(lucas.tail).map { pair =>
      p * pair._2 - q * pair._1
    }
    lucas
  }
}

fibo 基于 Fibonacci sequence example in Scala's Stream documentation,并且有效。

然而,试图用参数 pq 概括序列的 firstKind 函数(使得 Lucas sequences of the first kind)出现以下错误:

LucasSeq.scala:7: error: forward reference extends over definition of value lucas
    val lucas: Stream[Int] = 0 #:: 1 #:: lucas.zip(lucas.tail).map { pair =>
                                         ^
one error found

基本是一样的代码,为什么在函数外有效,在函数内却不行?


这个错误信息让我之前的很多程序员都疑惑过。我考虑过……

我可能会继续阅读几个小时,但我认为此时最好寻求帮助。我正在寻找解决方案和解释。 (我熟悉函数式编程,但对 Scala 不熟悉,所以如果解释涉及 "synthetic" 和 "implicit" 等术语,那么我可能还需要对此进行额外解释。)

这里有一个回答,但不知为何被删除了。

基本上有两种选择。您可以将 val 变成 lazy val。或者您可以将 class 中的 lucas: Stream[Int] 定义为字段。您可以在构造函数中使用 pq 参数化 class。

你是对的,原来的代码是偷懒的。但是scala翻译它还不够懒。

为了简单起见,考虑一下 val a = 1 + a 将翻译什么代码(我知道代码没有多大意义)。在 Java int a = 1 + a 中将不起作用。 Java 将尝试在 1 + a 中使用 a,但 a 尚未初始化。即使 Java 有 Integer a = 1 + a,并且 a 将是一个引用,Java 仍然无法执行此操作,因为 Java 运行 1 + a 语句分配 a

所以它留给我们两个选择。定义 a 不是变量,而是字段。 Scala 通过定义递归方法而不是字段来自动解决问题 - 因为 Scala 中的字段无论如何都是两种方法 + 变量。或者您可以明确地告诉 scala 它应该通过将您的 val 指定为 lazy val 来解决此处的惰性问题。这将使 scala 生成一个隐藏的 class,其中包含所有必要的基础设施,使其变得懒惰。

您可以通过 运行 带有 -print 选项的编译器来检查此行为。虽然输出相当复杂,尤其是在 lazy val 的情况下。

另请注意,因为您的流离开了范围,也因为您的流有两个参数 - pq,如果您使用 lazy val选项。如果您选择创建一个额外的 class - 您可以通过为每个 pq 可能的

缓存此 class 的所有实例来控制它

P.S。我在这里说 Java 当然是指 JVM。用 Java

来思考更容易