Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Почему в Scala можно назначать рекурсивные лямбда-выражения неленивым val?

Автор вопроса: corazzaОтветов: 1

В следующем операторе val f определяется как лямбда, которая ссылается сама на себя (это рекурсия):

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)?

recursionlambdascalaspecificationsdefinition

Ответы

Ответ 1 · рейтинг 7 · kiritsuku

Вероятно, вы пытались использовать это в REPL, который заключает все содержимое в определение объекта. Это важно, потому что в Scala (или лучше: в JVM) все значения экземпляра инициализируются значением по умолчанию, которое равно null для всех AnyRefs и 0, 0.0 или false для 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 }
                                                           ^

Такое поведение может даже привести к странным ситуациям, поэтому следует быть осторожным с рекурсивными значениями экземпляра:

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

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

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы