2012-05-04 8 views
6

Actualmente estoy aprendiendo Scala trabajando en el libro "Programación en Scala". Hasta ahora, no han sido buenas explicaciones para todo lo que se ve raro (desde la perspectiva de un programador de Java), pero este ejemplo utilizando una corriente para generar la secuencia de Fibonacci me deja tipo de perplejo:¿Cómo se traduce Stream-cons # :: en Scala?

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

¿Cómo es la construcción de la corriente? Por supuesto, el operador #:: es de alguna manera responsable de eso. Entiendo que, dado que termina en :, es de asociación correcta, pero eso no explica la creación de la transmisión. Supongo que está traducido implícitamente a un constructor de alguna manera, pero no veo por qué y cómo exactamente.

Ya he buscado respuestas en Predef.scala y LowPriorityImplicits.scala pero hasta ahora no tuve suerte.

¿Alguien puede aclararme?

Respuesta

8

Es asociativo derecho por lo que funciona como un método en el argumento de la derecha:

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

Al menos eso es lo que trata de hacer sintácticamente. Stream[Int] no tiene dicho método. Afortunadamente, object Stream tiene un implícito en alguna clase ConsWrapper que tiene este método (code).

Por lo tanto, lo que se obtiene después de la resolución implícita es la siguiente:

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

Gracias, eso es todo. Olvidé que las conversiones implícitas también se pueden definir en el objeto complementario de la clase que se debe convertir. – rolve

+5

Scaladoc probablemente debería incluir automáticamente las implicidades complementarias codificadas. – Debilski

+2

Quizás señale a otros nuevos en Scala que no es justo que sea correcto asociativo. También es que ConsWrapper implementa '# ::' como [call-by-name] (https://github.com/scala/scala/blob/v2.10.3/src/library/scala/collection/immutable/Stream. scala # L1042). es decir, el '⇒' en' ConsWrapper (tl: ⇒ Stream [A]) 'de modo que la traducción a' inmutable.this.Stream.consWrapper (fibFrom (b, a + b)). #: :(a) 'significa 'fibFrom (b, a + b)' solo se llamará cuando se acceda. – nicerobot

2

Una secuencia es similar a una lista. Solo conoce su cabeza y el resto de la corriente: Corriente (cabeza: T, cola: Corriente [T]). La diferencia es que una corriente se evalúa perezosamente. El ':' al final del nombre del método dice que el método es asociativo correcto. Entonces la expresión a # :: fibFrom (b, a + b) es traducida (por el compilador) a fibFrom (b, a + b). #: :(a).

+0

Gracias, eso es lo que pensé, pero no explica cómo se crea el objeto Stream. Si Stream tuviera un método '# ::', supondría una recursión infinita. – rolve

+0

El # :: es el mismo que :: en la lista. Y sí, es una recursión infinita. Simplemente toma la cantidad de elementos que desea. Eso fue lo que quería expresar diciéndole que es evaluado perezosamente. Esto significa que solo se calculará cuando haya necesidad de computación. –

+0

No es exactamente lo mismo, no. Si fuera lo mismo, tendrías una recursión infinita allí. En su lugar, '# ::' (definido en Class 'ConsWrapper', no Stream!) Tiene un parámetro de nombre que se evalúa con pereza. – rolve

Cuestiones relacionadas