La siguiente tabla muestra la precedencia de los operadores que más utilizamos en Haskell. A mayor número mayor precedencia. Por ejemplo, el operador +
tiene mayor precedencia que <
, por lo tanto si escribimos:
3 < 4 + 5
se entiende como:
3 < (4+5)
La tabla (simplificada) es la siguiente:
-- Primero vienen las funciones prefijas (como even, map, etc.) y luego los chirimbolos:
infixr 9 .
infixl 9 !!
infixr 8 ^, ^^, **
infixl 7 *, /, `quot`, `rem`, `div`, `mod`, :, %
infixl 6 +, -
infixr 5 :
infixr 5 ++
infix 4 ==, /=, <, <=, >=, >, `elem`, `notElem`
infixr 3 &&
infixr 2 ||
infixr 0 $
Eso significa que el signo pesos (la función $
) tiene muy poca precedencia, va a ser la “última” en considerarse. Y por el contrario las funciones prefijas (como el even
o el abs
) van a tener mucha precedencia. Entonces esta cuenta:
abs 3 - 5 -- Se lee como "le resto 5 al valor absoluto de 3"
Debe leerse como “le resto 5 al valor absoluto de 3”, porque eso es lo que significa en Haskell, porque la aplicación prefija de abs
tiene más precedencia que el -
. El resultado de esa cuenta es (-2)
(negativo).
Lo mismo sucede acá:
4 > 2 * 3 -- Se lee como "quiero saber si el 4 es mayor a la multiplicación entre 2 y 3"
Se lee así porque el >
tiene menos precedencia que el *
, entonces el *
se hace primero
Por último, para romper la precedencia se usan paréntesis. Si yo quiero decir “el valor absoluto de la resta entre 3 y 5” lo que debo hacer es:
abs (3 - 5) -- Se lee como "el valor absoluto de la resta entre 3 y 5"
Ver Uso del signo pesos en Haskell para ver cómo se aprovecha que el $
tenga tan poca precedencia.
Las palabras clave infixl
e infixr
permiten indicar la asociatividad del operador. Los operadores definidos con infixl
asocian a izquierda, mientras que los infixr
asocian a derecha. Por lo tanto, la expresión:
3 + 4 + 5
Se evalúa como:
(3 + 4) + 5
Ya que el operador asocia a izquierda. En cambio la expresión:
2:3:4:[]
Se debe leer como:
2:(3:(4:[]))
Ya que el operador asocia a derecha, al igual que la composición (.
), por ejemplo:
snd . head . filter even
Debe leerse como:
snd . (head . filter even)
También puede notarse que todos los operadores tienen menor precedencia que la aplicación funcional, es decir que al ejemplo anterior podríamos definirlo completamente si agregamos los paréntesis alrededor de .
:
snd . (head . (filter even))
Los operadores definidos como infix
no son asociativos, por ejemplo el operador de igualdad ==
. Por lo tanto la expresión:
a == b == c
No se entiende como (a == b) == c
ni como a == (b == c)
; la expresión sin paréntesis es incorrecta.