2010-07-05 6 views
17

Ich bin ziemlich neu in Scala Programmiersprache, und versuchte etwas aus meinem Kopf stecken, während ich die Vorlesungsnotizen bei here folgte.Understanding Infix-Methode Call-and-Cons-Operator (: :) in Scala

Ich glaube, ich konnte nicht wirklich verstehen, wie cons Operator funktioniert, hier sind einige Dinge, die ich versucht:

ich eine Pseudo-Zufallszahlengenerator erstellt haben, dann versucht, eine Liste mit einem Zufallswert zu erstellen:

scala> val gen = new java.util.Random 
gen: java.util.Random = [email protected] 

scala> gen nextInt 3 :: Nil 
<console>:7: error: type mismatch; 
found : List[Int] 
required: Int 
     gen nextInt 3 :: Nil 
        ^

Aber es versuchte, List (3) zu nächsten Methode zu übergeben. Wenn ich paratheses verwendet, gibt es kein Problem war

scala> (gen nextInt 3) :: Nil 
res69: List[Int] = List(1) 

Ich war neugierig auf die Ausführungsreihenfolge, so habe ich eine Funktion, es zu überprüfen

scala> def pr(i:Int):Int = { println(i); i } 
pr: (i: Int)Int 

scala> pr(1) :: pr(2) :: pr(3) :: Nil 
1 
2 
3 
res71: List[Int] = List(1, 2, 3) 

Wie in Ausgänge zu sehen ist, ist die Ausführungsreihenfolge die gleiche wie die Reihenfolge des Auftretens. Dann dachte ich, es über die ‚nextInt‘ Funktion sein könnte, dann habe ich versucht, folgende:

scala> 1 + 2 :: Nil 
res72: List[Int] = List(3) 

Es zuerst ausgeführt hinaus und nach, dass die Nachteile ausgeführt wird. Also hier ist die Frage: Was ist der Unterschied zwischen gen nextInt 3 :: Nil und 1 + 2 :: Nil?

Antwort

39

Es gibt zwei Dinge, die hier eine Rolle spielen: precedence und fixity. Wie Sepp2k erwähnt, erklärt diese Frage zu Stack Overflow den Vorrang, dachte, die Regeln seien nicht vollständig genug, und es gab sehr kleine Änderungen von Scala 2.7 zu Scala 2.8. Die Unterschiede betreffen jedoch hauptsächlich Operatoren, die auf = enden.

Wie für Fixität, wird fast alles in Scala von links nach rechts gelesen, was Programmierer gewöhnt sind. In Scala hingegen werden Operatoren mit der Endung : von rechts nach links gelesen.

nehmen, dann dieses Beispiel:

1 + 2 :: Nil 

zunächst Vorrang. Was hat am meisten Vorrang, + oder :? Entsprechend der Tabelle hat + Vorrang vor :, so dass die Addition zuerst erfolgt. Daher ist der Ausdruck dieser gleich:

((1).+(2)) :: Nil 

Jetzt gibt es keinen Vorrang Konflikt, aber da :: in : endet, hat es eine diferent fixity.Es wird von rechts nach links zu lesen, deshalb:

Nil.::((1).+(2)) 

Auf der anderen Seite, in dieser:

gen nextInt 3 :: Nil 

Der Betreiber :: Vorrang vor nextInt hat, weil : Vorrang vor allen Buchstaben hat. Aus diesem Grund und seiner Unveränderlichkeit erinnern, wird es:

gen nextInt Nil.::(3) 

die dann

gen.nextInt(Nil.::(3)) 

An diesem Punkt wird der Fehler offensichtlich ist.

PS: Ich bin (1).+(2) statt 1.+(2) zu schreiben, weil zum Zeitpunkt des Schreibens dieses Artikels, 1. als Doppelnummer interpretiert, 1.+(2) einen Infix Ausdruck Zugabe des Doppel 1,0 bis 2. Diese Syntax wie der Scala ist veraltet 2.10.0, und wird wahrscheinlich nicht auf Scala 2.11 vorhanden sein.

+0

Vielen Dank für Ihre ausführliche Antwort, es gab mir viele Hinweise auf viele andere Dinge. Aber ich habe noch eine Frage: Wie interpretiert der Compiler den Ausdruck in der dritten Codeabschnitt, den ich in meiner ersten Frage gab; in Klammern ausgedrückt? weil die Verwendung der Funktion pr gezeigt hat, dass die Ausdrücke in der Reihenfolge von links nach rechts ausgeführt werden. – ciuncan

+1

Richtig, die Funktionsaufrufe werden von links nach rechts ausgewertet. Das liegt daran, dass 'pr (X)' die Argumentausdrücke von '::' sind und diese zuerst in der Reihenfolge ihrer Erscheinung ausgewertet werden und dann der Wert an die Methode übergeben wird. 'pr (1) :: pr (2) :: pr (3) :: Nil 'druckt 1 2 3. Aber' Nil.::(pr(3)).::(pr(2)). :: (pr (1)) 'druckt 3 2 1. Aber beide geben' List (1, 2, 3) zurück ' –

+0

@ciuncan weiß ich nicht. Es kann sein, dass die Operatornotation mit der richtigen Fixität eine Bewertungsreihenfolge ermöglicht, die mit der Punktnotation nicht möglich ist, oder es könnte sein, dass der Compiler '::' Aufrufe optimiert, aber einen Fehler bezüglich der Bewertungsreihenfolge hat. –

3

Es geht um Rangfolge nicht Ausführungsreihenfolge. + hat höhere Priorität als ::, also a + b :: c analysiert als (a + b) :: c. Infix-Methodenaufrufe mit regulären Namen haben jedoch eine niedrigere Priorität, sodass a foo b c als a foo (b c) analysiert wird.

Eine Liste der Operatoren, die nach ihrer Priorität in scala geordnet sind, finden Sie unter this question.

+1

Danke für Ihre Erklärung. Vorrang war das, woran ich gerade nicht denken konnte. – ciuncan