Voici trois langages qui vous permettent de définir vos propres opérateurs, qui font deux choses et demie différentes ! Haskell et Coq interdisent tous les deux ces sortes de manigances - mais différemment - tandis qu'Agda permet ce genre de mélange d'associativités.
Tout d'abord, à Haskell , vous n'êtes tout simplement pas autorisé à le faire. Vous pouvez définir vos propres opérateurs et leur donner la priorité (de 0 à 9) et l'associativité de votre choix. Cependant, le rapport Haskell vous interdit de mélanger les associativités :
Les opérateurs consécutifs non entre parenthèses avec la même priorité doivent tous deux être associatifs à gauche ou à droite pour éviter une erreur de syntaxe. [Rapport Haskell 2010, chap. 3]
Donc, dans GHC , si nous définissons un infixl
opérateur associatif gauche ( ) <@
et un opérateur associatif droit @>
au même niveau de priorité - disons 0 - alors l'évaluation x <@ y @> z
donne l'erreur
L'erreur d'analyse de priorité
ne peut pas mélanger ' <@
' [ infixl 0
] et ' @>
' [ infixr 0
] dans la même expression d'infixe
(En fait, vous pouvez également déclarer un opérateur infixe mais non associatif, comme ==
, c'est x == y == z
donc une erreur de syntaxe!)
D'un autre côté, il y a le prouveur de langage / théorème de type dépendant Agda (qui, il est vrai, est considérablement moins courant). Agda possède certaines des syntaxes les plus malléables de toutes les langues que je connais, prenant en charge les opérateurs mixfix : la bibliothèque standard contient la fonction
if_then_else_ : ∀ {a} {A : Set a} → Bool → A → A → A
qui, une fois appelé, est écrit
if b then t else f
avec les arguments remplissant les traits de soulignement! Je mentionne cela parce que cela signifie qu'il doit prendre en charge une analyse incroyablement flexible. Bien entendu, Agda a aussi des déclarations de fixité (bien que ses niveaux de priorité vont nombres naturels plus arbitraires, et sont généralement en 0-100), et Agda ne vous permettra de mélanger les opérateurs de même priorité mais différents fixités. Je ne peux cependant pas trouver d'informations à ce sujet dans la documentation, j'ai donc dû expérimenter.
Réutilisons notre <@
et @>
d'en haut. Dans les deux cas simples, nous avons
x <@ y @> z
analyse en tant que x <@ (y @> z)
; et
x @> y <@ z
analyse en tant que (x @> y) <@ z
.
Je pense que ce qu'Agda fait est de regrouper la ligne en morceaux "associatifs de gauche" et "associatifs de droite", et - à moins que je ne pense à des choses erronées - le morceau associatif de droite obtient la "priorité" en saisissant les arguments adjacents. Cela nous donne donc
a <@ b <@ c @> d @> e @> f <@ g
analyse en tant que
(((a <@ b) <@ (c @> (d @> (e @> f)))) <@ g
ou
Cependant, malgré mes expériences, je me suis trompé la première fois que j'ai écrit cela, ce qui pourrait être instructif :-)
(Et Agda, comme Haskell, a des opérateurs non associatifs, qui donnent correctement des erreurs d'analyse, il serait donc possible que les associativités mixtes entraînent également une erreur d'analyse.)
Enfin, il y a le langage Coq , prouveur de théorèmes / type dépendant , qui a une syntaxe encore plus flexible que Agda parce que ses extensions de syntaxe sont en fait implémentées en donnant des spécifications pour les nouvelles constructions syntaxiques, puis en les réécrivant dans le langage de base (vaguement de type macro , Je suppose). Dans Coq, la syntaxe de liste [1; 2; 3]
est une importation facultative de la bibliothèque standard. De nouvelles syntaxes peuvent même lier des variables!
Encore une fois, dans Coq, nous pouvons définir nos propres opérateurs d'infixe et leur donner des niveaux de priorité (de 0 à 99, principalement) et des associativités. Cependant, dans Coq, chaque niveau de priorité ne peut avoir qu'une seule associativité . Donc, si nous définissons <@
comme associative à gauche, puis essayons de définir @>
comme associative à droite au même niveau - disons, 50 - nous obtenons
Erreur: le niveau 50 est déjà déclaré associatif de gauche alors qu'il devrait désormais être associatif de droite
La plupart des opérateurs de Coq sont à des niveaux divisibles par 10; si j'ai eu des problèmes d'associativité (ces associativités de niveau sont globales), j'ai généralement juste augmenté le niveau d'un dans les deux sens (généralement vers le haut).