2012-05-04 18 views
6

Attualmente sto imparando Scala lavorando sul libro "Programming in Scala". Finora, ci sono stati piacevoli spiegazioni per tutto ciò che sembra strano (dal punto di vista di un programmatore Java), ma questo esempio, utilizzando un flusso per generare la sequenza di Fibonacci mi lascia tipo di perplesso:In che modo Stream-cons # :: viene tradotto in Scala?

def fibFrom(a: Int, b: Int): Stream[Int] = 
    a #:: fibFrom(b, a + b) 

Come è la costruzione del flusso fatto? Ovviamente l'operatore #:: è in qualche modo responsabile di ciò. Capisco che dal momento che termina in :, è giusto-associativo, ma che non spiega la creazione del flusso. Immagino sia implicitamente tradotto in qualche modo da un costruttore, ma non vedo perché e come esattamente.

Ho già cercato risposte in Predef.scala e LowPriorityImplicits.scala ma finora non ho avuto fortuna.

Qualcuno può illuminarmi?

risposta

8

E 'associativa giusto in modo che funziona come un metodo sull'argomento destra:

fibFrom(b, a + b).#::(a) 

Almeno questo è quello che cerca di fare sintatticamente. Stream[Int] non ha un tale metodo. Fortunatamente, object Stream ha implicitamente una classe ConsWrapper che ha questo metodo (code).

Quindi, quello che si ottiene dopo la risoluzione implicita è questa:

immutable.this.Stream.consWrapper(fibFrom(b, a + b)).#::(a) 
+0

Grazie, è tutto. Ho dimenticato che le conversioni implicite possono anche essere definite nell'oggetto associato della classe che deve essere convertito. – rolve

+5

Scaladoc dovrebbe probabilmente includere automaticamente gli impliciti associati hard-coded. – Debilski

+2

Forse segnalare ad altri nuovi di Scala che non è giusto che sia giusto associare. È anche che ConsWrapper implementa '# ::' come [call-by-name] (https://github.com/scala/scala/blob/v2.10.3/src/library/scala/collection/immutable/Stream. Scala # L1042). cioè il '⇒' in' ConsWrapper (tl: ⇒ Stream [A]) 'in modo che la traduzione in' immutable.this.Stream.consWrapper (fibFrom (b, a + b)). #: :(a) ' 'FibFrom (b, a + b)' sarà sempre chiamato solo quando si accede. – nicerobot

2

Un flusso è simile a un elenco. Conosce solo la sua testa e il resto del flusso: Stream (testa: T, coda: Stream [T]). La differenza è che un flusso viene valutato pigramente. Il ':' alla fine del nome del metodo dice che il metodo è giusto associativo. Quindi l'espressione a # :: fibFrom (b, a + b) è tradotta (dal compilatore) in fibFrom (b, a + b). #: :(a).

+0

Grazie, è quello che ho capito, ma non spiega come viene creato l'oggetto Stream. Se Stream avesse un metodo '# ::', ciò causerebbe una ricorsione infinita, immagino. – rolve

+0

Il codice # :: è lo stesso di :: in List. E sì è una ricorsione infinita. Prendi solo il numero di elementi che desideri. Era quello che volevo esprimere dicendo che è pigramente valutato. Questo significa che sarà appena calcolato quando c'è bisogno di computer. –

+0

Non è esattamente lo stesso, no. Se fosse lo stesso, avresti una ricorsione infinita lì. Invece, '# ::' (definito in Classe 'ConsWrapper', non Stream!) Ha un parametro di nome che viene valutato pigramente. – rolve

Problemi correlati