Domanda

Ho imparato Scala e devo dire che si tratta di un linguaggio davvero cool. Mi piace soprattutto la sua capacità di pattern matching e letterali di funzione, ma io vengo da un javascript, sfondo rosso rubino e uno dei miei modelli preferiti in tali lingue è il modello di definizione della funzione e il metodo pigro. Un esempio in JavaScript è

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

Lo stesso codice con minime modifiche lavora in Ruby in cui è sufficiente utilizzare l'oggetto Singleton per ridefinire il metodo dopo l'esecuzione della computazione. Questo genere di cose viene in molto utile quando costoso calcolo sono coinvolti e non si sa in anticipo se si sta andando ad avere bisogno del risultato. So che in scala posso usare una cache per simulare lo stesso tipo di risultato, ma io sto cercando di evitare i controlli condizionali e risultati negativi fino ad ora i miei esperimenti sono tornati. Qualcuno sa se c'è una funzione o un metodo modello pigro definizione a Scala?

Nota: il codice JavaScript è da Peter Michaux sito <. / p>

È stato utile?

Soluzione

Tutto ciò che il codice complicato in JavaScript sembra provare solo per memorizzare nella cache il valore della data. In Scala, è possibile ottenere la stessa cosa banalmente:

lazy val foo = new Date

E, se non voglio nemmeno fare una val, ma consiglia di chiamare una funzione che solo eseguire il codice costoso se ne ha bisogno, puoi

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

dove il expensive: => String modello è chiamato un parametro per nome, che si può pensare come, "Dammi qualcosa che genererà una stringa su richiesta." Si noti che se si utilizza due volte, si rigenera ogni volta, che è dove a portata di mano modello Randall Schultz' è disponibile in:

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

Ora si genera solo se ne avete bisogno (tramite il parametro per nome) e memorizzarlo e il riutilizzo, se se ne ha bisogno (tramite la val pigro).

Quindi fare in questo modo, non il modo in JavaScript, anche se si potrebbero make Scala guardare un po 'come il JavaScript.

Altri suggerimenti

Scala ha lazy vals, i cui inizializzatori non vengono valutati a meno che e fino a quando la val viene utilizzato. vals pigri possono essere utilizzati come variabili locali del metodo.

Scala ha anche per nome i parametri del metodo, la cui attuale parametro espressioni sono avvolti in un thunk e che thunk viene valutata ogni volta che il parametro formale viene fatto riferimento nel corpo del metodo.

Insieme, questi possono essere utilizzati per ottenere pigri semantica di valutazione, come sono di default in Haskell (almeno nella mia molto limitata comprensione di Haskell).

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

In questo metodo, l'espressione utilizzata come parametro effettivo sarà valutata sia zero volte (se il percorso di esecuzione dinamica del corpo del metodo non utilizza ii) o una volta (se utilizza uno ii o più volte).

È possibile definire un val pigro che è una funzione:

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

println(foo())

foo() tornerà ora lo stesso oggetto Date di volta in volta, oggetto che verrà inizializzato la prima volta foo è chiamata.

viene eseguito

Per spiegare il codice un po ', la prima volta foo () viene chiamato { val d = new Date; () => { d } }, d viene assegnato a un nuovo valore di data allora valutare l'ultimo () => { d } espressione e assegnarlo al valore foo. Poi foo è una funzione senza parametri che d ritorno.

Credo che alcuni dei soccorritori erano un po 'confuso dal modo in cui si formulato la domanda. Il costrutto Scala si vuole qui è una semplice definizione pigro:

lazy val foo = new java.util.Date

La costruzione dell'oggetto Date avverrà al massimo una volta ed essere differito fino al primo riferimento a foo.

I nulla Rubino noto, ma Scala ha modello oggetto Singleton anche:

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> 

Se si desidera ottenere la funzione, si può rendere sottotipo di un tipo di funzione:

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

Credo che quello che vuoi dire "la funzione pigro" è la funzione letterale o funzione anonima.

In Scala si potrebbe fare cose come questa, molto simile al codice javascript che avete inviato.

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

    foo()
}

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

La differenza principale è che:

  • Non si poteva ri-assegnazione del foo esterno
  • Non v'è alcuna parola chiave "funzione", invece si usa qualcosa come (s: String) => {code}
  • L'ultima affermazione è il valore di ritorno di un blocco, quindi non c'è bisogno di aggiungere "ritorno".
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top