Wie definiert man einen ternären Operator in Scala, der führende Tokens erhält?

8

Ich schreibe einen Code-Generator, der Scala-Ausgabe erzeugt.

Ich muss einen ternären Operator so emulieren, dass die Token zu '?' bleiben intakt.

z.B. Konvertiere den Ausdruck c ? p : q in c something . Das einfache if(c) p else q scheitert an meinen Kriterien, da if( vor c gesetzt werden muss.

Mein erster Versuch (immer noch mit c / p / q wie oben) ist

%Vor%

Eine andere Option, die ich fand, war:

%Vor%

was mir erlaubt zu schreiben:

%Vor%

Ich mag das allgemeine Aussehen der zweiten Option, aber gibt es eine Möglichkeit, es weniger ausführlich zu machen?

Danke

    
Alex R 24.04.2010, 19:54
quelle

4 Antworten

14

Obwohl die Syntax nicht in der erwarteten Reihenfolge ausgewertet wird - sie bindet die Bedingung an die erste Option! - können Sie Ihren eigenen ternären Operator wie folgt erstellen:

%Vor%

Der Trick besteht darin, ? als Methode für ein MakeIfTrue -Objekt zu interpretieren, das die Bedingung an das Objekt bindet, das im "wahren" Fall zurückgegeben werden soll. Das resultierende IfTrue -Objekt verwendet nun die | -Methode als Anfrage, um die Bedingung auszuwerten, wobei die gespeicherte True-Option zurückgegeben wird, wenn die Bedingung wahr ist, oder die gerade übergebene, wenn sie falsch ist.

Beachten Sie, dass ich Sachen wie => A anstatt nur A - Namensparameter verwendet habe, um den Ausdruck nicht auszuwerten, es sei denn, er wird tatsächlich verwendet. Daher werten Sie nur die Seite aus, die Sie tatsächlich benötigen (genau wie eine if-Anweisung).

Sehen wir es in Aktion:

%Vor%

(P.S. Um Verwechslungen mit der Actor-Bibliothek ? zu vermeiden, sollten Sie es wahrscheinlich etwas anderes nennen wie |? .)

    
Rex Kerr 24.04.2010, 20:44
quelle
14

Lass es uns einfach machen:

Java:

%Vor%

Scala:

%Vor%

Neben der Einfachheit ist es klar und schnell, weil: Sie keine Objekte zuweisen, die Sie nicht benötigen, hält den Garbage Collector aus der Gleichung heraus (wie es immer sein sollte) und verwendet besser Prozessor-Caches.

    
Richard Gomes 07.08.2011 19:27
quelle
4

Sie könnten so etwas verwenden

%Vor%

Dieser Code konvertiert jeden booleschen Wert in einen anonymen Typ mit einer Methode namens ? . Abhängig vom Wert des booleschen Werts gibt diese Methode entweder TernarySecond oder TernaryThird zurück. Beide haben eine Methode namens > , die den zweiten Operanden bzw. den dritten Operanden zurückgibt.

    
Michel Krämer 24.04.2010 20:45
quelle
0

Ternärer Operator, der meine Verbesserung zu den besten Implementierungen von Rex Kerr und Michel Krämer hinzufügt:

  • Meine Verbesserung, um die neue Scala-Wertklasse zu verwenden, um Box-Overhead zu vermeiden.
  • Benennen Sie den 2. und 3. Operanden, so dass nur der ausgewählte Operand ausgewertet wird.
  • Michels Aufruf von by-value auf dem ersten (booleschen) Operanden, um Namensnennungen zu vermeiden; es wird immer ausgewertet.
  • Rex 'konkrete Klasse für die Bedingung, um anonyme Klassengemeinkosten zu vermeiden.
  • Michel bewertet die Bedingung, um zu bestimmen, welche Klasse zu konstruieren ist, um den Overhead eines Konstruktors mit zwei Argumenten zu vermeiden.

.

%Vor%

Beachten Sie, dass die Verbesserung gegenüber if else nicht nur die 6 gespeicherten Zeichen ist. Da die Syntax von Scala IDE für Schlüsselworte identisch ist (z. B. violett) für if , else , null und true , gibt es in einigen Fällen einen besseren Kontrast (was durch die Syntaxfarbe unten nicht gezeigt wird) wie derzeit auf dieser Website dargestellt):

%Vor%     
Shelby Moore III 14.11.2014 09:05
quelle