2016-05-06 6 views
3

Ich habe ein Stück Code, der eine Serie ist die Berechnung:Streams in Scala

object Problem7 extends App { 
    lazy val ps: Stream[Int] = 2 #:: Stream.from(3).filter(i => 
    ps.takeWhile(j => j * j <= i).forall(i % _ > 0)) 

    val r = ps(10000) 
    println(r) 
} 

hier ps ist vom Typ Sammel-Stream, die tatsächlich eine Variable ist, sondern wie sein mögliches es zu nennen wie diese ps(10000) als nicht jede Methode und ich habe auch noch einen Ausdruck val fs:Stream[Int] = 0 #:: fs.scanLeft(1)(_ + _), hier auch bin ich ein wenig mehrdeutig darüber, wie wir fs.scanLeft(1)(_+_) in der Variablen selbst aufrufen.Einige Hilfe !!

+0

Gibt es einen Grund, warum Sie keine Methode anstelle einer Variablen deklarieren? –

+0

kein Grund, nur zu versuchen zu verstehen, wie es funktioniert – Aamir

Antwort

3

hier ps ist vom Typ Sammel-Stream, die tatsächlich eine Variable ist aber wie sein mögliches es zu nennen wie diese ps (10000) als nicht jede Methode

Es ist möglich, ps(10000) weil Stream zu nennen hat eine apply Methode (geerbt von LinerSeqOptimized):

/** Selects an element by its index in the $coll. 
* Note: the execution of `apply` may take time proportial to the index value. 
* @throws `IndexOutOfBoundsException` if `idx` does not satisfy `0 <= idx < length`. 
*/ 
def apply(n: Int): A = { 
    val rest = drop(n) 
    if (n < 0 || rest.isEmpty) throw new IndexOutOfBoundsException("" + n) 
    rest.head 
} 

() auf jedem Objekt aufrufen in Scala lässt den Compiler nach einer apply Methode auf dem Objekt suchen. Dies ist vergleichbar mit der Möglichkeit, Fallklassen ohne das Schlüsselwort new zu instanziieren, da der Compiler automatisch apply und unapply für Sie generiert.

Wenn wir ein einfacheres reproduce aussehen werden:

def main(args: Array[String]): Unit = { 
    val ps: Stream[Int] = Stream.from(1, 1) 
    val r = ps(1) 
    println(r) 
} 

Der Compiler tatsächlich tut:

val r = ps.apply(1) 

Wo apply für eine Sammlung in der Regel das Element am Index nachschlägt i:

scala> val ps: Stream[Int] = Stream.from(1, 1) 
ps: Stream[Int] = Stream(1, ?) 

scala> val r = ps(1) 
r: Int = 2 

scala> val x = ps.apply(1) 
x: Int = 2 

Wenn Sie tatsächlich sehen wollen, was die comp Iler erzeugt:

object Problem7 extends Object { 
    def main(args: Array[String]): Unit = { 
     val ps: scala.collection.immutable.Stream = scala.`package`.Stream().from(1, 1); 
     val r: Int = scala.Int.unbox(ps.apply(1)); 
     scala.this.Predef.println(scala.Int.box(r)) 
    }; 

    def <init>(): Problem7.type = { 
     Problem7.super.<init>(); 
    () 
    } 
    } 
} 
+0

gute Erklärung – Aamir

+0

@Aamir Vielen Dank! . –

+0

würde Sie über eine kleine Erklärung zu diesem 'val fs: Stream [Int] = 0 # :: fs.scanLeft (1) (_ + _)' denken, ich weiß, wie scanleft funktioniert, aber wie sein Aufruf 'fs.scanLeft' ist ein wenig zweifelhaft – Aamir

1

Für den zweiten Teil der Frage,

lazy val fs:Stream[Int] = 0 #:: fs.scanLeft(1)(_ + _) 

Die # :: ist cons Operator Stream.cons zum Konstruieren Strömen verwendet. Der Parameter ConsWrapper ist ein by-name-Parameter und wird daher träge ausgewertet.

Es ist daher zulässig, fs nach dem Operator # :: zu referenzieren. Ich denke, wir müssen das Val zu Lazy Val ändern, sonst wirft der Scala-Compiler die Referenz über die Definition des Wertes fs hinaus.