2016-06-12 9 views
1

Ich kratze mich an einem Beispiel, das ich in Brees Dokumentation über distributions gesehen habe.scala for/yield on fall der Klasse

Nach einer Rand-Instanz erstellen, zeigen sie, dass Sie Folgendes tun:

import breeze.stats.distributions._ 

val pois = new Poisson(3.0); 
val doublePoi: Rand[Double] = for(x <- pois) yield x.toDouble 

Nun, dies ist sehr cool, ich kann ein Rand Objekt bekommen, dass ich Double statt Int bekommen kann, wenn ich rufe die samples Methode. Ein anderes Beispiel könnte sein:

val abc = ('a' to 'z').map(_.toString).toArray 
val letterDist: Rand[String] = for(x <- pois) yield { 
val i = if (x > 26) x % 26 else x 
abc(i) 
} 
val lettersSamp = letterDist.samples.take(20) 
println(letterSamp) 

Die Frage ist, was hier vor sich geht? Rand[T] ist keine Sammlung, und alle For/Yield-Beispiele, die ich bisher gesehen habe, arbeiten an Sammlungen. Die Scala-Dokumente erwähnen nicht viel, das einzige, was ich gefunden habe, ist das Übersetzen von For-Comprehensions in here. Was ist die zugrunde liegende Regel hier? Wie sonst kann dies verwendet werden (muss nicht eine Briese bezogene Antwort sein)

+2

LIke in der Verbindung erwähnt, eine für das Verständnis ist im Grunde syntaktischer Zucker für eine Kombination von 'flatMap's und einer' map'. Sie können ein Verständnis schreiben, weil ['Poisson'] (http://www.scalanlp.org/api/breeze/#breeze.stats.distributions.Poisson) sowohl' flatMap' als auch 'map' implementiert. In Ihrem Fall ist das für das Verständnis analog zu 'pois.map (_. ToDouble)'. –

+0

Auch eine zufällige Verteilung * ist * eine Sammlung.Es ist eine ziemlich seltsame Sammlung, die ** ** ** ** ** ** ** enthält ** und nicht ** definitiv ** enthält ** spezifische ** Elemente, aber Sie können es als eine Sammlung interpretieren. (Ein Bloom-Filter ist ein noch seltsamer, wenn Sie darüber nachdenken.) –

Antwort

0

Für Verständnis sind nur syntaktischer Zucker für flatMap, Karte und withFilter. Die Hauptvoraussetzung für die Verwendung in einem Verständnis ist, dass diese Methoden implementiert sind. Sie sind daher nicht auf Sammlungen beschränkt, z. Einige allgemeine Nicht-Sammlungen, die für das Verständnis verwendet werden, sind Option, Try und Future.

In Ihrem Fall scheint Poisson von einem Zug Rand genannt

definiert

https://github.com/scalanlp/breeze/blob/master/math/src/main/scala/breeze/stats/distributions/Rand.scala

Diese Eigenschaft hat Karte, flatmap und withFilter zu erben.

Tipp: Wenn Sie eine IDE wie IntelliJ verwenden - Sie alt drücken + für das Verständnis auf Ihre Eingabe und wählte konvertieren Ausdruck entzuckert und Sie werden sehen, wie es sich ausdehnt.

1

Scala hat Regeln für die Übersetzung for und for-yield Ausdrücke auf die entsprechenden flatMap und map Anrufe, gegebenenfalls auch Filter anwenden withFilter und eine solche Verwendung. Die tatsächliche Spezifikation, wie Sie die Ausdrücke für den Verständnisausdruck in die entsprechenden Methodenaufrufe übersetzen, finden Sie in der Scala-Spezifikation unter this section.

Wenn wir Ihr Beispiel nehmen und es kompilieren, werden wir sehen, dass die zugrundeliegende Umwandlung mit dem Ausdruck for-yield geschieht. Dies geschieht mit Hilfe scalac -Xprint:typer Befehl, um die Art Bäume auszudrucken:

val letterDist: breeze.stats.distributions.Rand[String] = 
     pois.map[String](((x: Int) => { 
      val i: Int = if (x.>(26)) 
      x.%(26) 
      else 
      x; 
      abc.apply(i) 
})); 

Hier können Sie sehen, dass for-yield verwandelt sich in einen einzigen map vorbei in einem Int und die if-else innerhalb der Ausdruck anwenden. Das funktioniert, weil Rand[T] has a map method definiert:

def map[E](f: T => E): Rand[E] = MappedRand(outer, f)