Pregunta

He estado aprendiendo Scala y tengo que decir que es un lenguaje muy fresco. Me gusta especialmente sus capacidades de coincidencia de patrones y literales de función pero vengo de un javascript, fondo rubí y una de mis patrones favoritos en esos idiomas es la función y el método de definición de patrón perezoso. Un ejemplo en JavaScript es

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

El mismo código con ajustes menores trabaja en el rubí en el que sólo utiliza el objeto singleton para redefinir el método después de que se realiza el cálculo. Este tipo de cosas viene en muy práctico cuando cómputo caros están involucrados y no se sabe de antemano si va a tener el resultado. Sé que en Scala puedo usar una memoria caché para simular el mismo tipo de resultado, pero estoy tratando de evitar los controles condicionales y los resultados negativos hasta ahora mis experimentos han regresado. ¿Alguien sabe si hay una función o un método de definición de patrón flojo en Scala?

Nota: El código Javascript es de Pedro Michaux sitio <. / p>

¿Fue útil?

Solución

Todo lo que complica el código en JavaScript parece simplemente tratar de almacenar en caché el valor de la fecha. En Scala, se puede lograr la misma cosa trivial:

lazy val foo = new Date

Y, si ni siquiera quieren hacer un val, pero que desee llamar a una función que sólo se ejecutará el código caro si lo necesita, puede

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

donde el expensive: => String patrón se llama un parámetro por nombre, que se puede considerar como "Dame algo que va a generar una cadena de petición." Tenga en cuenta que si se utiliza dos veces, se regenerará cada vez, que es donde el patrón útil Randall Schultz entra en juego:

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

Ahora se genera sólo si lo necesita (a través del parámetro por nombre) y almacenarla y reutilización que si lo necesite de nuevo (a través del val perezoso).

Así que hacerlo de esta manera, no es la manera de JavaScript, a pesar de que podría Scala que se parecen mucho a la de JavaScript.

Otros consejos

Scala tiene lazy vals, cuya inicializadores no son evaluados a menos que y hasta que se utiliza el val. Vals Lazy se pueden utilizar como variables locales de método.

Scala también tiene por nombre parámetros del método, cuyo parámetro real expresiones están envueltos en un golpe seco y se evalúa que thunk cada vez que el parámetro formal se hace referencia en el cuerpo del método.

En conjunto, estos pueden ser utilizados para lograr la semántica evaluación perezosa, como son el valor por defecto en Haskell (al menos en mi muy limitada comprensión de Haskell).

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

En este método, la expresión se utiliza como el parámetro real será evaluado ya sea cero veces (si la ruta de ejecución dinámica del cuerpo del método nunca utiliza ii) o una vez (si se utiliza uno ii o más veces).

Se puede definir un val perezoso, que es una función:

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

println(foo())

foo() volverá ahora la misma Fecha de objeto cada vez, objeto que se inicializa la primera vez que se llama foo.

se ejecuta

Para explicar el código un poco, la primera vez foo () se llama { val d = new Date; () => { d } }, d es asignado a un nuevo valor de fecha entonces evaluar la última () => { d } expresión y asignarlo al valor foo. Entonces foo es una función sin parámetros que d retorno.

Creo que algunos de los que respondieron eran un poco confundido por la forma en que formul la pregunta. La construcción Scala usted quiere aquí es una definición perezoso simple:

lazy val foo = new java.util.Date

La construcción del objeto Date ocurrirá en más de una vez y ser diferido hasta que la primera referencia a foo.

Yo nada sobre Ruby conocido, pero tiene Scala modelo objeto Singleton también:

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> 

Si desea obtener la función, se puede hacer subtipo de un tipo de función:

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

Creo que lo que quiere decir "función perezoso" es literal función o función anónima.

En Scala que podía hacer cosas como esta, muy similar al código Javascript informados.

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

    foo()
}

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

La diferencia principal es que:

  • Usted no podía reasignación del foo exterior
  • No hay palabras clave "función", en lugar de utilizar algo así como (s): String => {code}
  • La última afirmación es el valor de retorno de un bloque, por lo que no es necesario añadir "retorno".
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top