Der Kontext dafür ist ziemlich einfach. Meine Annahmen basieren auf Oderskys Buch "Programming in Scala, 2. Auflage", Abschnitt 8.5, "Platzhaltersyntax".
Ich habe eine Liste [List [Boolean]] (d. h. eine rechteckige Bitmap), in der ich versuche, das gesamte Vorkommen des Wertes "wahr" zu zählen. Hier ist die REPL-Zeile, die die Daten definiert, die in Ordnung sind:
%Vor%Als nächstes versuchte ich, die Vorkommen von "wahr" mit der folgenden Zeile zu zählen. Und anstatt zu führen, erhalte ich einen Fehler:
%Vor%Ich habe den Fehler nicht verstanden, da die beiden Unterstriche die Parameter für die Funktion darstellen. Also habe ich die Funktion expliziter gemacht, indem ich das geschrieben habe, was gut funktioniert:
%Vor%Meine Frage ist folgende: Warum habe ich für den weniger expliziten Fall einen Fehler erhalten und Fehler, aber wenn ich die Funktion durch Reduzierung der "Vereinfachungen" abbilde, wird sie korrekt ausgeführt?
Danke für jede Einsicht, die Sie mir dazu geben können.
Die Einschränkungen von Scalas Platzhaltersyntax für anonyme Funktionen können sehr verwirrend sein (zumindest für mich). Eine Faustregel besagt, dass Unterstriche an ihre nächsten umschließenden Klammern gebunden werden, aber dies ist eine Näherung - siehe Abschnitt 6.23 von die Scala-Spezifikation für das Detail:
Ein Ausdruck e der syntaktischen Kategorie
Expr
bindet an einen Unterstrich Abschnitt u , wenn die folgenden zwei Bedingungen zutreffen: (1) e richtig enthält u und (2) gibt es keinen anderen syntaktischen Ausdruck categoryExpr
, die korrekt in e enthalten ist und welche selbst enthält korrekt u .
In diesem Fall sieht der Compiler den zweiten Unterstrich nicht als zweiten Parameter. Dies mag seltsam erscheinen, da _ + _
richtigerweise zwei Parameter hat und if (_) x else y
äquivalent zu z => if (z) x else y
ist (wobei z
ein neuer Bezeichner ist), aber die Verschachtelung der beiden funktioniert nicht.
Es stimmt, dass der Compiler theoretisch herausfinden konnte, dass die zwei Unterstriche Parameter für die gleiche anonyme Funktion in Ihrem foldLeft
sein sollten, aber nicht im folgenden Beispiel, wo der Der zweite Unterstrich muss wirklich separat gebunden werden:
Dies würde jedoch eine Menge extra Cleverness seitens des Compilers erfordern, und die Scala-Sprachdesigner haben entschieden, dass es sich nicht lohnt - dass Platzhalter-Syntax nur für einige ziemlich einfache Fälle ohne verschachtelte Ausdrücke bereitgestellt werden muss.
Glücklicherweise können Sie in diesem Fall einfach rowsByColumns.flatten.count(identity)
schreiben. flatten
verkettet hier die Unterlisten zu einem einzelnen List[Boolean]
. Wir möchten dann wissen, wie viele der Werte in dieser Liste true
sind. count
nimmt ein Prädikat und sagt Ihnen, wie viele Werte in einer Sammlung dieses Prädikat erfüllen. Zum Beispiel gibt es eine Möglichkeit, die geraden Zahlen zwischen 1 und 10 (inklusive) zu zählen:
In Ihrem Fall haben wir jedoch bereits boolesche Werte, daher muss das Prädikat keine Arbeit verrichten - es kann nur die Identitätsfunktion x => x
sein. Wie dhg in einem Kommentar feststellt, stellt Scala's Predef
-Objekt dies als a dar Methode namens identity
, die ich hier verwende. Sie könnten genauso gut rowsByColumns.flatten.count(x => x)
schreiben, wenn Sie das klarer finden.
Wir können Ihre Frage untersuchen, indem wir einen einfacheren Fall betrachten:
%Vor%Der Fehler, den wir sehen, ist
%Vor% Was passiert ist also, dass Scala _
in (x) => x
auf engstem Raum erweitert. Mit anderen Worten, es versucht zu tun:
aber das ist falsch.
Ihr Fall ist ähnlich. Die beiden _
werden nicht so behandelt, als wären beide im selben Umfang, weshalb sie der Meinung sind, dass es nur einen Parameter gibt. Der zweite _
wird innerhalb des Bereichs if
erweitert, was falsch ist. Es denkt, dass du das tust:
Wenn Sie weitere Überlegungen anstellen, gibt es eine Chance, dass Oderskys Vorschlag ( in SIP 12 ), um Scalas Syntax zu ändern, um die erforderlichen Klammern im Bewertungsausdruck von if zu entfernen, würde seinen "Fehler" korrigieren, so dass die ursprüngliche fehlerhafte Anweisung durch Entfernen der Klammern aus if wieder korrekt ausgeführt würde
Hinweis (August 216, 4 Jahre später): Die Entscheidung ist
auf eine zukünftige Veröffentlichung verschoben
Dieses SIP befindet sich derzeit im Status "Zurückgestellt" mit der aktuellen Aktion für 2.10.
- (1) Vernachlässige "
then
" in Kennungen, um den zukünftigen Schlüsselwortstatus zu reservieren.- (2) Vernachlässige die problematische "
while() do
" -Syntax. ("do
" Schleifen in While-Schleifen erfordern geschweifte Klammern).Ursprünglich im Jahr 2011 vorgeschlagen, schlug der Vorschlag Syntaxänderungen in
if
's,for
undwhile
loops vor, was die Syntax von Scala von Java und C-ähnlichen Sprachen abwandelte.
In der Erwägung, dass solche Änderungen möglicherweise schöner sind, war der Ausschuss der Meinung, dass dies mehr Probleme als Vorteile bringen würde.
Siehe Problem 555
Tags und Links scala