Ich verstehe die Ausbeute von Ruby und Python. Was macht Scalas Ertrag?
312
Ich verstehe die Ausbeute von Ruby und Python. Was macht Scalas Ertrag?
Es wird in Sequenzverständnissen verwendet (wie Pythons Listenverständnis und Generatoren, wo Sie es auch verwenden können yield
).
Es wird in Kombination mit angewendet for
und schreibt ein neues Element in die resultierende Sequenz.
Einfaches Beispiel (von scala-lang )
/** Turn command line arguments to uppercase */
object Main {
def main(args: Array[String]) {
val res = for (a <- args) yield a.toUpperCase
println("Arguments: " + res.toString)
}
}
Der entsprechende Ausdruck in F # wäre
[ for a in args -> a.toUpperCase ]
oder
from a in args select a.toUpperCase
in Linq.
Ruby's yield
hat einen anderen Effekt.
Ich denke, die akzeptierte Antwort ist großartig, aber es scheint, dass viele Menschen einige grundlegende Punkte nicht verstanden haben.
Erstens entspricht Scalas
for
Verständnis dem von Haskelldo
Notation , und es ist nichts weiter als ein syntaktischer Zucker für die Zusammensetzung mehrerer monadischer Operationen. Da diese Aussage höchstwahrscheinlich niemandem helfen wird, der Hilfe benötigt, versuchen wir es noch einmal… :-)Scalas
for
Verständnis ist syntaktischer Zucker für die Komposition mehrerer Operationen mit KarteflatMap
undfilter
. Oderforeach
. Scala übersetzt einenfor
Ausdruck tatsächlich in Aufrufe dieser Methoden, sodass jede Klasse, die sie bereitstellt, oder eine Teilmenge davon zum Verständnis verwendet werden kann.Lassen Sie uns zunächst über die Übersetzungen sprechen. Es gibt sehr einfache Regeln:
Diese
wird übersetzt in
Diese
wird übersetzt in
Diese
wird auf Scala 2.7 in übersetzt
oder auf Scala 2.8 in
mit einem Fallback in die erstere, wenn Methode
withFilter
nicht verfügbar ist, aberfilter
ist. Weitere Informationen hierzu finden Sie im folgenden Abschnitt.Diese
wird übersetzt in
Wenn Sie sich sehr einfache
for
Erkenntnisse ansehen, sehen diemap
/foreach
Alternativen tatsächlich besser aus. Sobald Sie mit dem Komponieren beginnen, können Sie sich jedoch leicht in Klammern und Verschachtelungsebenen verlieren. Wenn dies geschieht, ist dasfor
Verständnis normalerweise viel klarer.Ich werde ein einfaches Beispiel zeigen und absichtlich jede Erklärung weglassen. Sie können entscheiden, welche Syntax leichter zu verstehen war.
oder
withFilter
In Scala 2.8 wurde eine Methode namens aufgerufen
withFilter
, deren Hauptunterschied darin besteht, dass anstelle einer neuen, gefilterten Sammlung bei Bedarf gefiltert wird. Dasfilter
Verhalten der Methode wird basierend auf der Strenge der Sammlung definiert. Um dies besser zu verstehen, werfen wir einen Blick auf einige Scala 2.7 mitList
(streng) undStream
(nicht streng):Der Unterschied tritt auf, weil
filter
sofort angewendetList
wird und eine Liste der Gewinnchancen zurückgegeben wird - dafound
istfalse
. Erst dannforeach
wird ausgeführt, aber zu diesem Zeitpunkt ist eine Änderungfound
bedeutungslos, wiefilter
bereits ausgeführt.Im Falle von
Stream
wird die Bedingung nicht sofort angewendet. Testen Sie stattdessen, wie jedes Element von angefordert wirdforeach
,filter
die Bedingung,foreach
um sie zu beeinflussenfound
. Um es klar zu machen, hier ist der äquivalente Code für das Verständnis:Dies verursachte viele Probleme, da die Leute erwarteten
if
, dass das On-Demand-Verfahren berücksichtigt wird, anstatt es zuvor auf die gesamte Sammlung anzuwenden.Es wurde Scala 2.8 eingeführt
withFilter
, die unabhängig von der Strenge der Sammlung immer nicht streng ist. Das folgende Beispiel zeigtList
mit beiden Methoden in Scala 2.8:Dies führt zu dem Ergebnis, das die meisten Menschen erwarten, ohne das Verhalten zu ändern
filter
. Als RandnotizRange
wurde zwischen Scala 2.7 und Scala 2.8 von nicht streng zu streng geändert.quelle
withFilter
soll auch für strenge Sammlungen nicht streng sein, was eine Erklärung verdient. Ich werde das in Betracht ziehen ...for(x <- c; y <- x; z <-y) {...}
wird übersetzt inc.foreach(x => x.foreach(y => y.foreach(z => {...})))
2.for(x <- c; y <- x; z <- y) yield {...}
wird übersetzt inc.flatMap(x => x.flatMap(y => y.map(z => {...})))
for(x <- c; y = ...) yield {...}
wirklich übersetztc.map(x => (x, ...)).map((x,y) => {...})
? Ich denke, es ist übersetztc.map(x => (x, ...)).map(x => { ...use x._1 and x._2 here...})
oder ich vermisse etwas?Ja, wie Earwicker sagte, es ist so ziemlich das Äquivalent zu LINQs
select
und hat sehr wenig mit Rubys und Pythons zu tunyield
. Grundsätzlich, wo in C # würden Sie schreibenin Scala haben Sie stattdessen
Es ist auch wichtig zu verstehen, dass
for
-Verständnis nicht nur mit Sequenzen funktioniert, sondern mit jedem Typ, der bestimmte Methoden definiert, genau wie LINQ:map
, erlaubt erfor
Ausdrücke, die aus einem einzelnen Generator bestehen.flatMap
so gut wie definiertmap
, erlaubt esfor
Ausdrücke, die aus mehreren Generatoren bestehen.foreach
, erlaubt esfor
-schleifen ohne Ausbeute (sowohl mit einem als auch mit mehreren Generatoren).filter
, werdenfor
-filter-Ausdrücke zugelassen, die mit einemif
imfor
Ausdruck beginnen.quelle
Sofern Sie keine bessere Antwort von einem Scala-Benutzer erhalten (was ich nicht bin), ist hier mein Verständnis.
Es wird nur als Teil eines Ausdrucks angezeigt
for
, der mit beginnt und angibt, wie eine neue Liste aus einer vorhandenen Liste generiert wird.Etwas wie:
Es gibt also ein Ausgabeelement für jede Eingabe (obwohl ich glaube, dass es eine Möglichkeit gibt, Duplikate zu löschen).
Dies unterscheidet sich erheblich von den "imperativen Fortsetzungen", die durch die Ausbeute in anderen Sprachen ermöglicht werden. Dort können Sie eine Liste beliebiger Länge aus einem imperativen Code mit nahezu beliebiger Struktur erstellen.
(Wenn Sie mit C # vertraut sind, ist es dem
select
Operator von LINQ näher als demyield return
).quelle
Das Schlüsselwort
yield
in Scala ist einfach syntaktischer Zucker, der leicht durch a ersetzt werden kannmap
, wie Daniel Sobral bereits ausführlich erklärt hat.Auf der anderen Seite
yield
ist es absolut irreführend, wenn Sie nach Generatoren (oder Fortsetzungen) suchen, die denen in Python ähnlich sind . Weitere Informationen finden Sie in diesem SO-Thread: Was ist der bevorzugte Weg, um 'Yield' in Scala zu implementieren?quelle
Beachten Sie zum Verständnis Folgendes
Es kann hilfreich sein, es wie folgt laut vorzulesen
„ Für jede ganze Zahl
i
, wenn sie größer als3
, dann ergibt (produzieren)i
und füge sie die ListeA
.“In Bezug auf die mathematische Set-Builder-Notation ist das obige Verständnis analog zu
was gelesen werden kann als
„ Für jede ganze Zahl , wenn sie größer als , dann ist ein Mitglied des Satzes .“
oder alternativ als
" ist die Menge aller ganzen Zahlen , so dass jede größer als ist ."
quelle
Die Ausbeute ähnelt der for-Schleife mit einem Puffer, den wir nicht sehen können, und fügt für jedes Inkrement das nächste Element zum Puffer hinzu. Wenn die for-Schleife beendet ist, wird die Sammlung aller erhaltenen Werte zurückgegeben. Die Ausbeute kann als einfache arithmetische Operatoren oder sogar in Kombination mit Arrays verwendet werden. Hier sind zwei einfache Beispiele zum besseren Verständnis
res: scala.collection.immutable.IndexedSeq [Int] = Vektor (3, 6, 9, 12, 15)
res: Seq [(Int, Char)] = Liste ((1, a), (1, b), (1, c), (2, a), (2, b), (2, c), ( 3, a), (3, b), (3, c))
Hoffe das hilft!!
quelle
Diese beiden Codeteile sind äquivalent.
Diese beiden Codeteile sind ebenfalls gleichwertig.
Die Karte ist so flexibel wie der Ertrag und umgekehrt.
quelle
Der Ertrag ist flexibler als map (), siehe Beispiel unten
Ausbeute druckt Ergebnis wie folgt: Liste (5, 6), was gut ist
while map () gibt das folgende Ergebnis zurück: List (false, false, true, true, true), was wahrscheinlich nicht das ist, was Sie beabsichtigen.
quelle