2010-07-05 18 views
17

Soy bastante nuevo en el lenguaje de programación Scala, y estaba intentando algo en mi mente mientras estaba siguiendo las notas de la conferencia al here.Entender el operador de llamadas y contras del método infix (: :) en Scala

Creo que realmente no podía entender cómo funciona contras operador, aquí hay algunas cosas que intenté:

que he creado un generador de números pseudo-aleatorios, luego trató de crear una lista de un valor aleatorio:

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 
        ^

Pero intentó pasar la Lista (3) al método siguiente. Cuando solía paratheses, no había ningún problema

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

tenía curiosidad acerca de la orden de ejecución, por lo que creó una función para comprobar que

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) 

Como se ve en las salidas, orden de ejecución es el mismo que el orden de aparición Entonces pensé que podría ser sobre la función 'nextInt', entonces intenté siguiente:

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

En primer lugar, ejecutados Además, y después de que los contras se ejecuta. Entonces aquí está la pregunta: ¿Cuál es la diferencia entre gen nextInt 3 :: Nil y 1 + 2 :: Nil?

Respuesta

39

Hay dos cosas que preocupan aquí: precedence y fixity. Como mencionó Sepp2k, esta pregunta sobre Desbordamiento de pila explica la precedencia, aunque las reglas citadas no son lo suficientemente completas, y hubo cambios muy pequeños desde Scala 2.7 hasta Scala 2.8. Las diferencias se refieren principalmente a operadores que terminan en =, sin embargo.

En cuanto a fixity, casi todo en Scala se lee de izquierda a derecha, que es a lo que los programadores están acostumbrados. En Scala, sin embargo, los operadores que terminan en : se leen de derecha a izquierda.

Toma, pues, este ejemplo:

1 + 2 :: Nil 

En primer lugar, la precedencia. ¿Qué tiene más prioridad, + o :? De acuerdo con la tabla, + tiene prioridad sobre :, por lo que la adición se hace primero. Por lo tanto, la expresión es igual a esto:

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

Ahora no hay conflicto precedencia, pero desde :: termina en :, que tiene una fijeza diferent.Se lee de derecha a izquierda, por lo tanto:

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

Por otro lado, en este:

gen nextInt 3 :: Nil 

El operador :: tiene prioridad sobre nextInt, porque : tiene prioridad sobre todas las letras. Por lo tanto, y recordando su fijeza, se convierte en:

gen nextInt Nil.::(3) 

que luego se convierte

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

Momento en el que el error es evidente.

PS: Estoy escribiendo (1).+(2) en lugar de 1.+(2) porque, en el momento de escribir estas líneas, 1. se interpreta como un número doble, haciendo 1.+(2) una expresión infija añadiendo el doble de 1,0 a 2. Esta sintaxis está obsoleta de Scala 2.10.0, y probablemente no estará presente en Scala 2.11.

+0

Gracias por su respuesta detallada, también me dio muchas pistas sobre muchas otras cosas. Pero tengo una pregunta más: ¿Cómo interpreta el compilador la expresión en la sección del tercer código que di en mi pregunta inicial; en términos de paréntesis? porque usar la función pr mostró que los términos se ejecutan en el orden de izquierda a derecha. – ciuncan

+1

Correcto, las llamadas a funciones se evalúan de izquierda a derecha. Esto es porque 'pr (X)' son las expresiones de argumento de '::' y estas se evalúan primero en orden de aparición y luego el valor se pasa al método. 'pr (1) :: pr (2) :: pr (3) :: Nil' prints 1 2 3. Pero' Nil.::(pr(3)).::(pr(2)). : :(pr (1)) 'imprime 3 2 1. Pero ambos regresan' List (1, 2, 3) ' –

+0

@ciuncan No lo sé. Es posible que la notación del operador con la corrección correcta permita una orden de evaluación que no sea posible con la notación de puntos, o podría ser que el compilador optimice las llamadas '::' pero tenga un error relacionado con el orden de la evaluación. –

3

Se trata de orden de precedencia y no ejecución. + tiene una precedencia mayor que ::, por lo que a + b :: c analiza como (a + b) :: c. Sin embargo, las llamadas al método infix con nombres regulares tienen una precedencia más baja, por lo que a foo b c se analiza como a foo (b c).

Consulte this question para obtener una lista de operadores ordenados por su precedencia en scala.

+1

Gracias por su explicación. La precedencia era en lo que solo echaba de menos pensar. – ciuncan

Cuestiones relacionadas