2010-09-20 19 views
23

Ho trovato che Scala ha sempre una "spiegazione naturale" per qualsiasi cosa. Sempre qualcosa come "ohh, ma è solo una funzione chiamata su questo e quell'oggetto con questo e quel parametro". In un certo senso, nulla è veramente magico per i compilatori, così come lo conosciamo da altre lingue.Scala "<-" per comprensione

La mia domanda è sul <- operatore utilizzato nel codice seguente:

for(i <- 0 to 10) println(i) 

In questo esempio posso vedere che sia riscritto a qualcosa di simile:

0.to(10).foreach((i:Int)=>println(i)) 

ma questo non spiega come lo i sia stato trasportato nell'anonimo funzione ymous all'interno della funzione foreach. Nel punto in cui scrivi i non è un oggetto e non è ancora una variabile dichiarata. Allora, cos'è e come viene trasportato all'interno di foreach?

La mia ipotesi è che ho finalmente scoperto qualcosa che è in realtà compilatore magia

Grazie per il vostro tempo.

Per chiarire, la mia domanda è: come fa il < - lavoro dell'operatore in 1 ° riga di codice dal momento che non è un oggetto su cui può essere definito come una funzione.

risposta

18

<- è un linguaggio -defined simbolo di parola chiave, come lo è => ma in netto contrasto con -> (che è un simbolo definito). Poiché fa parte della grammatica di base di Scala, può essere utilizzato per creare associazioni (per il i nell'esempio), che è qualcosa che non può essere fatto da costrutti definiti dall'utente.

+0

Questa sembra essere la risposta. Ti suggerirei di documentarlo se possibile, è un po 'strano in questo momento. – Felix

+4

@Felix: è documentato nelle specifiche. E praticamente ogni libro Scala disponibile sul mercato lo copre. – missingfaktor

+0

oh sì, non ho ancora ricevuto un libro. in attesa del libro definitivo 2.8 – Felix

6

In questo caso, è davvero un po 'di magia del compilatore. La conversione da for-comprehension a filter/map/flatmap è un po 'speciale di desugaring, proprio come la conversione delle forme speciali di aggiornamento e metodi di applicazione.

57

per aumentare la risposta di Dave, ecco uno schema di traduzione per 'for-comprensioni' da specifica del linguaggio Scala:

Una comprensione for (enums) yield e Valuta expression e per ogni legame generato da enumeratori enumerazioni. Una sequenza di enumeratori inizia sempre con un generatore; questo può essere seguito da ulteriori generatori, definizioni di valori o guardie.

Un generatore p <- e produce associazioni da un'espressione e che corrisponde in qualche modo al modello p. Una definizione di valore val p = e associa il valore nome p (o più nomi in un modello p) al risultato della valutazione dell'espressione e. Una guardia if e contiene un'espressione booleana che limita i binding numerati.

Il preciso significato di generatori e guardie è definita da una versione di invocazioni di quattro metodi: map, filter, flatMap e foreach. Questi metodi possono essere implementati in modi diversi per diversi tipi di operatore.

Lo schema di traduzione è il seguente. In un primo passaggio, ogni generatore p <- e, dove p non è irrefutabile (§8.1) per il tipo di e è sostituita da

p <- e.filter { case p => true; case _ => false } 

Poi, le seguenti regole vengono applicate ripetutamente finché tutti comprehensions sono stati eliminati.

  • A per-comprensione for (p <- e) yield e0 è tradotto in e.map { case p => e0 }.

  • A for-comprehension for (p <- e) e0 è tradotto in e.foreach { case p => e0 }.

  • A per-comprensione for (p <- e; p0 <- e0 . . .) yield e00, dove. . . è una sequenza (eventualmente vuota) di generatori o guardie, è tradotto a:
    e.flatMap { case p => for (p0 <- e0 . . .) yield e00 }.

  • A per-comprensione for (p <- e; p0 <- e0 . . .) e00 dove. . . è una sequenza (eventualmente vuota) di generatori o guardie, è tradotto in:
    e.foreach { case p => for (p0 <- e0 . . .) e00 }.

  • Un generatore p <- e seguita da una guardia if g viene traslato in un unico generatore:
    p <- e.filter((x1, . . . , xn) => g)
    dove x1,. . . , xn sono le variabili libere di p.

  • Un generatore p <- e seguito da una definizione valore val p0 = e0 è tradotto al seguente generatore di coppie di valori, dove x e x0 sono nomi freschi:

    val (p, p0) <- 
        for([email protected] <- e) yield { val [email protected] = e0; (x, x0) } 
    
+1

Ok, non capisco tutto dopo aver letto prima, ma è interessante :-) Dove hai preso questo? – Felix

+0

@Felix: Come ho detto all'inizio della risposta, è tratto dalla specifica della lingua (può essere scaricato da www.scala-lang.org) – missingfaktor

Problemi correlati