2014-07-17 79 views
2

在下面的語句瓦爾f被定義爲引用本身(它是遞歸)一個lambda:爲什麼可以將遞歸lambda分配給Scala中的非惰性vals?

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

我已經試過了在REPL,它編譯並正確執行。

根據規範,這似乎是非法向前引用的實例:

在一份聲明中序列s[1]...s[n]組成一個塊,如果簡單 名s[i]是指由s[j]這裏定義的實體j >= i, 那麼對於所有s[k]之間幷包括s[i]s[j]

  • s[k]不能是變量定義。
  • 如果s[k]是一個值定義,則它必須是lazy

分配是一個單一的語句,所以它滿足了j >= i標準,它被包括在所述兩個規則適用於(之間幷包括s[i]s[j])語句的間隔。

但是,它似乎違反了第二條規則,因爲f不是懶惰。

這是一個法律聲明(在Scala 2.9.2中試過)?

回答

7

您可能試圖在REPL中使用它,它將所有內容包裝在對象定義中。這是因爲在斯卡拉重要(或更好:在JVM)的所有實例值與默認值,這是null所有AnyRefs00.0falseAnyVals初始化。對於這個默認初始化不會發生的方法值,因此,你在這種情況下,得到一個錯誤信息:

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 } 
                 ^

這種行爲甚至可導致怪異的情況下,因此應該小心使用遞歸的實例值:

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

scala> val s: String = s+" x" 
s: String = null x 
+0

是的你是正確的,這是在REPL。我已經預感到它可能是這樣的,我知道Scala REPL必須在它背後有一些黑魔法(畢竟Scala是一種編譯語言,所以當我看到它甚至有一個REPL時,我有點困惑,我只是假設它收集了你之前輸入的所有語句,並將它們放在'def main'或其他東西中)。 – corazza

相關問題