Aqui estão três idiomas que permitem definir seus próprios operadores, que fazem duas coisas e meia diferentes ! Haskell e Coq proíbem esse tipo de travessuras - mas de maneira diferente - enquanto a Agda permite esse tipo de mistura de associatividades.
Primeiro, em Haskell , você simplesmente não tem permissão para fazer isso. Você pode definir seus próprios operadores e dar a eles a precedência (de 0 a 9) e a associatividade de sua escolha. No entanto, o Relatório Haskell não permite que você misture associatividades :
Operadores não parênteses consecutivos com a mesma precedência devem ser associativos à esquerda ou à direita para evitar um erro de sintaxe. [Relatório Haskell 2010, cap. 3]
Portanto, no GHC , se definirmos um infixl
operador associativo à esquerda ( ) <@
e associativo à direita @>
no mesmo nível de precedência - digamos 0 -, a avaliação x <@ y @> z
fornecerá o erro
O erro de análise de precedência
não pode misturar ' <@
' [ infixl 0
] e ' @>
' [ infixr 0
] na mesma expressão de infixo
(Na verdade, você também pode declarar que um operador é infixo, mas não associativo, como ==
, portanto, isso x == y == z
é um erro de sintaxe!)
Por outro lado, há o provador de idiomas / teoremas de tipo dependente Agda (que, reconhecidamente, é consideravelmente menos popular). A Agda possui algumas das sintaxes mais maleáveis de qualquer idioma que eu conheço, suportando operadores mixfix : a biblioteca padrão contém a função
if_then_else_ : ∀ {a} {A : Set a} → Bool → A → A → A
que, quando chamado, está escrito
if b then t else f
com os argumentos preenchendo os sublinhados! Menciono isso porque isso significa que ele precisa oferecer suporte à análise incrivelmente flexível. Naturalmente, Agda também tem declarações fixity (embora seus níveis de precedência variam números naturais mais arbitrárias, e são tipicamente em 0-100), e Agda faz permitir que você misturar operadores da mesma precedência, mas diferentes fixities. No entanto, não consigo encontrar informações sobre isso na documentação, então tive que experimentar.
Vamos reutilizar o nosso <@
e @>
de cima. Nos dois casos simples, temos
x <@ y @> z
analisando como x <@ (y @> z)
; e
x @> y <@ z
analisando como (x @> y) <@ z
.
Acho que o que a Agda faz é agrupar a linha em partes "associativas à esquerda" e "associativas à direita" e - a menos que eu esteja pensando em coisas erradas - o pedaço associativo à direita recebe "prioridade" ao agarrar os argumentos adjacentes. Então isso nos dá
a <@ b <@ c @> d @> e @> f <@ g
analisando como
(((a <@ b) <@ (c @> (d @> (e @> f)))) <@ g
ou
No entanto, apesar dos meus experimentos, adivinhei errado na primeira vez que escrevi isso, o que pode ser instrutivo :-)
(E a Agda, como Haskell, tem operadores não associativos, que fornecem erros de análise corretamente, portanto, seria possível que associatividades mistas resultem em um erro de análise também.)
Por fim, há a linguagem Coq , comprovadora de teoremas / de tipo dependente , que possui sintaxe ainda mais flexível que a Agda, porque suas extensões de sintaxe são realmente implementadas fornecendo especificações para as novas construções sintáticas e reescrevendo-as na linguagem principal (vagamente semelhante a macro , Eu suponho). No Coq, a sintaxe da lista [1; 2; 3]
é uma importação opcional da biblioteca padrão. Novas sintaxes podem até vincular variáveis!
Mais uma vez, no Coq, podemos definir nossos próprios operadores de infix e fornecer a eles níveis de precedência (de 0 a 99, principalmente) e associatividades. No entanto, no Coq, cada nível de precedência pode ter apenas uma associatividade . Portanto, se definirmos <@
como associativo à esquerda e tentarmos definir @>
como associativo à direita no mesmo nível - digamos, 50 - obteremos
Erro: o nível 50 já foi declarado associativo à esquerda, enquanto agora é esperado que seja associativo à direita
A maioria dos operadores em Coq está em níveis divisíveis por 10; se eu tive problemas de associatividade (essas associatividades de nível são globais), geralmente apenas aumentamos o nível em um em qualquer direção (geralmente acima).