Вопрос

Я изучал Scala, и я должен сказать, что это действительно крутой язык. Мне особенно нравится его возможности, соответствующие образу и функциональные литералы, но я прихожу из JavaScript, Ruby Background и один из моих любимых узоров на этих языках - это ленивая функция и определение метода. Пример в JavaScript

var foo = function() {
  var t = new Date();
  foo = function() {
    return t;
  };
  return foo();
};

Этот же код с незначительными настройками работает в Ruby, где вы просто используете объект Singleton для переопределения метода после выполнения вычислений. Такая вещь приходит в самом удобности, когда задействованы дорогих вычислений, и вы не знаете заранее, если вам понадобится результат. Я знаю, что в Scala я могу использовать кэш для имитации такого же результата, но я пытаюсь избежать условных проверок, и до сих пор мои эксперименты вернули отрицательные результаты. Кто-нибудь знает, есть ли ленивая функция или определение метода в Scala?

Примечание. Код JavaScript от Peter Michaux's сайт.

Это было полезно?

Решение

Все этот сложный код в JavaScript, кажется, просто попробуйте кэшировать значение даты. В Scala вы можете добиться того же тривиально:

lazy val foo = new Date

И, если даже не хотите сделать Val, но хотите вызвать функцию, которая будет выполнять только дорогой код, если это это нужно, вы можете

def maybeExpensive(doIt: Boolean, expensive: => String) {
  if (doIt) println(expensive)
}
maybeExpensive(false, (0 to 1000000).toString)  // (0 to 1000000).toString is never called!
maybeExpensive(true, (0 to 10).toString)        // It is called and used this time

где рисунок expensive: => String называется параметрами имени, который вы можете думать о том, что «дай мне что-то, что будет генерировать строку по запросу». Обратите внимание, что если вы используете его дважды, он будет регенерировать его каждый раз, который находится в том случае, если Handy Pattern Randall Schultz находится:

def maybeExpensiveTwice(doIt: Boolean, expensive: => String) {
  lazy val e = expensive
  if (doIt) {
    println(e)
    println("Wow, that was " + e.length + " characters long!")
  }
}

Теперь вы генерируете только в том случае, если вам это нужно (через параметр по имени) а также Храните его и повторно используйте его, если вам нужно это снова (через ленивый валь).

Так что делайте это так, а не хоть JavaScript, даже если вы мог Сделать Scala очень похоже на JavaScript.

Другие советы

Скала есть lazy vals, чьи инициализаторы не оцениваются, если и до тех пор, пока валь не используется. Ленивые валы могут быть использованы в качестве метода локальных переменных.

Scala также имеет параметры метода по имени, фактические выражения параметров которых завернуты в Thunk, и этот Thunk оценивается каждый раз, когда формальный параметр ссылается в корпусе метода.

Вместе они могут быть использованы для достижения ленивой оценки семантики, таких как значение по умолчанию в Haskell (по крайней мере, в моем очень ограниченном понимании Haskell).

def meth(i: => Int): Something = {
  //        ^^^^^^ by-name parameter syntax
  lazy val ii = i
  // Rest of method uses ii, not i
}

В этом методе выражение, используемое в качестве фактического параметра, будет оцениваться либо нулевым временем (если путь динамического выполнения метода тела никогда не использует ii) или один раз (если он использует ii один или несколько раз).

Вы можете определить ленивый валь, который является функцией:

lazy val foo = {
  val d = new Date
  () => { d }
}

println(foo())

foo() Теперь теперь вернет один и тот же объект даты каждый раз, объект, который будет инициализирован в первый раз, когда вызывается Foo.

Чтобы немного объяснить код, первый раз Foo () называется { val d = new Date; () => { d } } выполняется, d назначен новое значение даты, то он оценивает последнее выражение () => { d } и назначьте его значение FOO. Тогда foo - это функция без параметров, которые возвращают d.

Я думаю, что некоторые из респондентов были немного запутаны тем, как вы сформулировали вопрос. Scala Construct, вы хотите, - это простое ленивое определение:

lazy val foo = new java.util.Date

Строительство объекта даты будет происходить не более одного раз и отложить до первой ссылки на FOO.

Я ничего не знал о Ruby, но Scala имеет шаблон объекта Singleton также:

Welcome to Scala version 2.8.0.r22634-b20100728020027 (Java HotSpot(TM) Client VM, Java 1.6.0_20).
Type in expressions to have them evaluated.
Type :help for more information.

scala> object LazyInit {                                       
     |     val msec = { println("Hi,I'm here!");   System.currentTimeMillis }
     | }
defined module LazyInit

scala> System.currentTimeMillis                                              
res0: Long = 1282728315918

scala> println(System.currentTimeMillis +" : " + LazyInit.msec)              
Hi,I'm here!
1282728319929 : 1282728319930

scala> println(System.currentTimeMillis +" : " + LazyInit.msec)
1282728322936 : 1282728319930

scala> println(System.currentTimeMillis +" : " + LazyInit.msec)
1282728324490 : 1282728319930

scala> 

Если вы хотите получить функцию, вы можете сделать его подтипом типа функции:

scala> object LazyFun extends (() => Long) {            
     |     val msec = System.currentTimeMillis          
     |     def apply() = msec                           
     | }
defined module LazyFun

scala> System.currentTimeMillis                         
res2: Long = 1282729169918

scala> println(System.currentTimeMillis + " : " + LazyFun())
1282729190384 : 1282729190384

scala> println(System.currentTimeMillis + " : " + LazyFun())
1282729192972 : 1282729190384

scala> println(System.currentTimeMillis + " : " + LazyFun())
1282729195346 : 1282729190384

Я думаю, что вы имеете в виду «ленивый функция», является функциональной буквальной или анонимной функцией.

В Scala вы могли бы сделать такие вещи, как это, очень похоже на код JavaScript, который вы разместили.

val foo = () => {
    val t = new Date()
    val foo = () => {t}

    foo()
}

println ("Hello World:" + foo())

Основное отличие в том, что:

  • Вы не могли повторно назначить внешний FOO
  • Нет никаких «функциональных» ключевых слов, вместо этого вы используете что-то вроде (S: String) => {код}
  • Последнее утверждение - это возвращаемое значение блока, поэтому вам не нужно добавить «возвращение».
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top