Ecco tre lingue che ti consentono di definire i tuoi operatori, che fanno due cose e mezzo diverse ! Haskell e Coq entrambi non ammettono questo tipo di shenanigans - ma in modo diverso - mentre Agda consente questo tipo di mescolanza di associatività.
Innanzitutto, in Haskell , semplicemente non ti è permesso farlo. Puoi definire i tuoi operatori e dare loro la precedenza (da 0 a 9) e l'associatività di tua scelta. Tuttavia, il Rapporto Haskell non ti consente di mescolare associatività :
Gli operatori consecutivi non personalizzati con la stessa precedenza devono essere entrambi associativi di destra o di sinistra per evitare un errore di sintassi. [Rapporto Haskell 2010, cap. 3]
Quindi, in GHC , se definiamo un infixl
operatore associativo di sinistra ( ) <@
e un operatore associativo di destra @>
allo stesso livello di precedenza - diciamo 0 - allora la valutazione x <@ y @> z
dà l'errore
L'errore di analisi della precedenza
non può mescolare ' <@
' [ infixl 0
] e ' @>
' [ infixr 0
] nella stessa espressione infix
(In effetti, puoi anche dichiarare che un operatore è infisso ma non associativo ==
, quindi x == y == z
è un errore di sintassi!)
D'altra parte, c'è il prover del linguaggio / teorema tipicamente dipendente Agda (che, è vero, è notevolmente meno mainstream). Agda ha alcune delle sintassi più malleabili di qualsiasi lingua che conosca, supportando gli operatori di mixfix : la libreria standard contiene la funzione
if_then_else_ : ∀ {a} {A : Set a} → Bool → A → A → A
che, quando chiamato, è scritto
if b then t else f
con gli argomenti che riempiono i caratteri di sottolineatura! Ne parlo perché ciò significa che deve supportare l'analisi incredibilmente flessibile. Naturalmente, Agda ha anche dichiarazioni fissità (anche se i suoi livelli di precedenza spaziano numeri naturali sopra arbitrari, e sono in genere in 0-100), e Agda fa si permette di mescolare gli operatori con la stessa precedenza, ma diverse fissità. Tuttavia, non riesco a trovare informazioni al riguardo nella documentazione, quindi ho dovuto sperimentare.
Riutilizziamo il nostro <@
e @>
dall'alto. Nei due casi semplici, abbiamo
x <@ y @> z
analizzando come x <@ (y @> z)
; e
x @> y <@ z
analizzando come (x @> y) <@ z
.
Penso che quello che Agda fa sia raggruppare la linea in blocchi "associativi di sinistra" e "associativi di destra" e - a meno che non stia pensando a cose sbagliate - il pezzo associativo di destra ottiene "priorità" nell'afferrare gli argomenti adiacenti. Quindi questo ci dà
a <@ b <@ c @> d @> e @> f <@ g
analizzando come
(((a <@ b) <@ (c @> (d @> (e @> f)))) <@ g
o
Tuttavia, nonostante i miei esperimenti, ho indovinato la prima volta che l'ho scritto, il che potrebbe essere istruttivo :-)
(E Agda, come Haskell, ha operatori non associativi, che danno correttamente errori di analisi, quindi sarebbe possibile che anche associatività miste producano un errore di analisi.)
Infine, c'è il linguaggio teorema-prover / tipicamente dipendente Coq , che ha una sintassi ancora più flessibile di Agda perché le sue estensioni di sintassi sono effettivamente implementate dando specifiche per i nuovi costrutti sintattici e poi riscrivendole nel linguaggio principale (vagamente macro-like , Credo). In Coq, la sintassi dell'elenco [1; 2; 3]
è un'importazione opzionale dalla libreria standard. Le nuove sintassi possono anche associare le variabili!
Ancora una volta, in Coq, possiamo definire i nostri operatori infix e dare loro livelli di precedenza (da 0 a 99, per lo più) e associatività. Tuttavia, in Coq, ogni livello di precedenza può avere solo un'associatività . Quindi, se definiamo <@
associativa di sinistra e quindi proviamo a definire @>
associativa di destra allo stesso livello - diciamo 50 - otteniamo
Errore: il livello 50 è già dichiarato associativo di sinistra mentre ora si prevede che sia associativo di destra
La maggior parte degli operatori in Coq sono su livelli divisibili per 10; se ho avuto problemi di associatività (questi livelli di associatività sono globali), in genere ho semplicemente aumentato il livello di uno in entrambe le direzioni (di solito in alto).