为什么可以在Scala中为非惰性val分配递归lambda?

cor*_*zza 2 recursion lambda specifications scala definition

在以下语句中,val f被定义为引用自身的lambda(它是递归的):

val f: Int => Int = (a: Int) =>
    if (a > 10) 3 else f(a + 1) + 1 // just some simple function
Run Code Online (Sandbox Code Playgroud)

我在REPL中尝试过它,它编译并正确执行.

根据规范,这似乎是非法前向引用的一个例子:

s[1]...s[n]构成块的语句序列中,如果一个简单的名称是s[i]指由s[j]where 定义的实体j >= i,那么对于所有s[k]之间和包括s[i]s[j],

  • s[k] 不能是变量定义.
  • 如果s[k]是值定义,则必须是lazy.

赋值是单个语句,因此它满足j >= i条件,并且它包含在两个规则适用于(之间和包括s[i]s[j])之间的语句间隔中.

但是,它似乎违反了第二条规则,因为f它不是懒惰的.

这是一个法律声明(在Scala 2.9.2中尝试过)?

kir*_*uku 7

您可能尝试在REPL中使用它,它将所有内容包装在对象定义中.这很重要,因为在Scala中(或者更好:在JVM上),所有实例值都使用默认值进行初始化,该值null适用于所有AnyRefs0/ 0.0falsefor AnyVals.对于方法值,此默认初始化不会发生,因此在这种情况下您会收到错误消息:

scala> object x { val f: Int => Int = a => if (a > 10) 3 else f(a+1)+1 }
defined object x

scala> def x { val f: Int => Int = a => if (a > 10) 3 else f(a+1)+1 }
<console>:7: error: forward reference extends over definition of value f
       def x { val f: Int => Int = a => if (a > 10) 3 else f(a+1)+1 }
                                                           ^
Run Code Online (Sandbox Code Playgroud)

这种行为甚至可能导致奇怪的情况,因此应该注意递归实例值:

scala> val m: Int = m+1
m: Int = 1

scala> val s: String = s+" x"
s: String = null x
Run Code Online (Sandbox Code Playgroud)