Относительно ленивости - в настоящее время передача параметра в метод является строгой по умолчанию:
def square(a: Int) = a * a
, но вы используете параметры вызова по имени:
def square(a: =>Int) = a * a
но это не лениво в том смысле, что оно вычисляет значение только один раз при необходимости:
scala> square({println("calculating");5})
calculating
calculating
res0: Int = 25
Была проделана некоторая работа по добавлению метода lazy параметров, но он еще не был интегрирован (нижеприведенное объявление должно печатать "calculating"
сверху только один раз):
def square(lazy a: Int) = a * a
Это одна часть, которая отсутствует, хотя вы можете смоделировать ее с локальнымlazy val:
def square(ap: =>Int) = {
lazy val a = ap
a * a
}
Относительно изменчивости - ничто не мешает вам писать неизменяемые структуры данных и избегать мутаций.Вы можете сделать это в Java или C, а также.Фактически, некоторые неизменяемые структуры данных полагаются на ленивый примитив для достижения лучших границ сложности, но ленивый примитив может быть смоделирован и на других языках - за счет дополнительного синтаксиса и стандартного шаблона.
Вы всегда можете написать неизменные структуры данных, ленивые вычисления и полностью чистые программы в Scala.Проблема состоит в том, что модель программирования Scala также позволяет писать не чистые программы, поэтому средство проверки типов не всегда может вывести некоторые свойства программы (например, чистоту), которые она может вывести, учитывая, что модель программирования была более строгой.
Например, в языке с чистыми выражениями a * a
в приведенном выше определении вызова по имени (a: =>Int
) можно оптимизировать для оценки a
только один раз, независимо от вызова по именисемантика.Если язык допускает побочные эффекты, то такая оптимизация не всегда применима.