¡Aquí hay tres idiomas que le permiten definir sus propios operadores, que hacen dos cosas y media diferentes ! Haskell y Coq no permiten este tipo de travesuras, pero de manera diferente, mientras que Agda permite este tipo de mezcla de asociatividades.
Primero, en Haskell , simplemente no tienes permitido hacer esto. Puede definir sus propios operadores y darles la precedencia (de 0 a 9) y la asociatividad que elija. Sin embargo, el Informe Haskell no le permite mezclar asociatividades :
Los operadores consecutivos sin paréntesis con la misma precedencia deben ser asociativos izquierda o derecha para evitar un error de sintaxis. [Informe Haskell 2010, cap. 3]
Entonces, en GHC , si definimos un infixl
operador <@
asociativo @>
a la izquierda ( ) y un operador asociativo a la derecha en el mismo nivel de precedencia, digamos 0, entonces evaluar x <@ y @> z
da el error
El error de análisis de precedencia
no puede mezclar ' <@
' [ infixl 0
] y ' @>
' [ infixr 0
] en la misma expresión infija
(De hecho, también puede declarar que un operador es infijo pero no asociativo ==
, por lo que x == y == z
es un error de sintaxis).
Por otro lado, está el comprobador de lenguaje / teorema de tipo dependiente Agda (que, ciertamente, es considerablemente menos convencional). Agda tiene una de las sintaxis más maleables de cualquier lenguaje que conozco, y admite operadores mixfix : la biblioteca estándar contiene la función
if_then_else_ : ∀ {a} {A : Set a} → Bool → A → A → A
que, cuando se llama, está escrito
if b then t else f
con los argumentos llenando los guiones bajos! Menciono esto porque significa que debe admitir un análisis increíblemente flexible. Naturalmente, Agda también tiene declaraciones de fijeza (aunque sus niveles de precedencia oscilan sobre números naturales arbitrarios, y típicamente están en 0–100), y Agda le permite mezclar operadores de la misma precedencia pero con fijezas diferentes. Sin embargo, no puedo encontrar información sobre esto en la documentación, así que tuve que experimentar.
Reutilicemos nuestro <@
y @>
desde arriba. En los dos casos simples, tenemos
x <@ y @> z
analizando como x <@ (y @> z)
; y
x @> y <@ z
analizando como (x @> y) <@ z
.
Creo que lo que Agda hace es agrupar la línea en fragmentos "asociativos izquierdos" y "asociativos derechos", y, a menos que esté pensando en cosas incorrectas, el fragmento asociativo correcto obtiene "prioridad" al captar los argumentos adyacentes. Entonces eso nos da
a <@ b <@ c @> d @> e @> f <@ g
analizando como
(((a <@ b) <@ (c @> (d @> (e @> f)))) <@ g
o
Sin embargo, a pesar de mis experimentos, adiviné mal la primera vez que escribí eso, lo que podría ser instructivo :-)
(Y Agda, como Haskell, tiene operadores no asociativos, que dan errores de análisis correctamente, por lo que sería posible que las asociatividades mixtas también generen un error de análisis).
Finalmente, está el lenguaje Coq , que prueba el teorema / dependientemente , que tiene una sintaxis aún más flexible que Agda porque sus extensiones de sintaxis se implementan realmente al proporcionar especificaciones para las nuevas construcciones sintácticas y luego reescribirlas en el lenguaje central (vagamente como macro , Supongo). En Coq, la sintaxis de la lista [1; 2; 3]
es una importación opcional de la biblioteca estándar. ¡Las nuevas sintaxis incluso pueden unir variables!
Una vez más, en Coq, podemos definir nuestros propios operadores de infijo y darles niveles de precedencia (de 0 a 99, principalmente) y asociatividades. Sin embargo, en Coq, cada nivel de precedencia solo puede tener una asociatividad . Entonces, si definimos <@
como asociativo a la izquierda y luego intentamos definirlo @>
como asociativo a la derecha en el mismo nivel, digamos 50, obtenemos
Error: el nivel 50 ya se ha declarado asociativo a la izquierda, mientras que ahora se espera que sea asociativo a la derecha
La mayoría de los operadores en Coq están en niveles que son divisibles por 10; Si he tenido problemas de asociatividad (estas asociatividades de nivel son globales), generalmente he superado el nivel en uno en cualquier dirección (generalmente hacia arriba).