De ce este posibil să se atribuie lambda recursive valorilor non-leneși în Scala?

În următoarea declarație, val f este definit ca un lambda care se referă la sine (este recursiv):

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

L-am încercat în REPL și se compilează și se execută corect.

Conform specificației, aceasta pare a fi o instanță de referire directă ilegală:

Într-o secvență de instrucțiuni s[1]...s[n] care alcătuiește un bloc, dacă un nume simplu în s[i] se referă la o entitate definită de s[j] unde j >= i, atunci pentru toate s[k] între și inclusiv s[i] și s[j],

  • s[k] nu poate fi o definiție variabilă.
  • Dacă s[k] este o definiție de valoare, trebuie să fie lazy.

Atribuirea este o singură instrucțiune, deci a îndeplinit criteriile j >= i și este inclusă în intervalul de instrucțiuni la care se aplică cele două reguli (între și inclusiv s[i] și s[j]).

Cu toate acestea, se pare că încalcă a doua regulă, deoarece f nu este leneș.

Cum este aceasta o declarație legală (a încercat-o în Scala 2.9.2)?


person corazza    schedule 17.07.2014    source sursă


Răspunsuri (1)


Probabil ați încercat să utilizați acest lucru în REPL, care include tot conținutul într-o definiție a obiectului. Acest lucru este important deoarece în Scala (sau mai bine: pe JVM) toate valorile instanțelor sunt inițializate cu o valoare implicită, care este null pentru toate AnyRefs și 0, 0.0 sau false pentru AnyVals. Pentru valorile metodei, această inițializare implicită nu are loc, prin urmare veți primi un mesaj de eroare în acest caz:

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

Acest comportament poate duce chiar la situații ciudate, prin urmare ar trebui să fiți atenți la valorile instanțelor recursive:

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

scala> val s: String = s+" x"
s: String = null x
person kiritsuku    schedule 17.07.2014
comment
Da, ai dreptate, asta a fost în REPL. Am avut o bănuială că ar putea fi așa ceva, știam că Scala REPL trebuie să aibă ceva magie neagră în spate (Scala este un limbaj compilat până la urmă, așa că am fost puțin confuz când am văzut că avea chiar și un REPL - Am presupus că a colectat toate declarațiile pe care le-ai tastat înainte și le-a pus într-un def main sau ceva de genul ăsta). - person corazza; 18.07.2014