Hier sind drei Sprachen, mit denen Sie Ihre eigenen Operatoren definieren können, die zweieinhalb verschiedene Dinge tun ! Haskell und Coq verbieten beide diese Art von Spielereien - aber unterschiedlich -, während Agda diese Art der Vermischung von Assoziativitäten zulässt.
Erstens dürfen Sie dies in Haskell einfach nicht tun. Sie können Ihre eigenen Operatoren definieren und ihnen den Vorrang (von 0 bis 9) und die Assoziativität Ihrer Wahl geben. Der Haskell-Bericht verbietet Ihnen jedoch, Assoziativitäten zu mischen :
Aufeinanderfolgende nicht parästhesierte Operatoren mit derselben Priorität müssen entweder links oder rechts assoziativ sein, um einen Syntaxfehler zu vermeiden. [Haskell 2010 Report, Kap. 3]
Wenn wir also in GHC einen linksassoziativen ( infixl
) Operator <@
und einen rechtsassoziativen Operator @>
auf derselben Prioritätsstufe definieren - sagen wir 0 -, x <@ y @> z
ergibt die Auswertung den Fehler
Vorrang-Analysefehler
können ' <@
' [ infixl 0
] und ' @>
' [ infixr 0
] nicht im selben Infix-Ausdruck mischen
(Tatsächlich können Sie einen Operator auch als Infix deklarieren, aber nicht assoziativ ==
, so dass dies x == y == z
ein Syntaxfehler ist!)
Auf der anderen Seite gibt es den abhängig typisierten Sprach- / Theorembeweiser Agda (der zugegebenermaßen wesentlich weniger Mainstream ist). Agda hat einige der formbarsten Syntax aller mir bekannten Sprachen und unterstützt Mixfix- Operatoren: Die Standardbibliothek enthält die Funktion
if_then_else_ : ∀ {a} {A : Set a} → Bool → A → A → A
was, wenn es aufgerufen wird, geschrieben wird
if b then t else f
mit den Argumenten, die die Unterstriche ausfüllen! Ich erwähne dies, weil dies bedeutet, dass es unglaublich flexibles Parsen unterstützen muss. Natürlich Agda hat auch fixity Erklärungen (obwohl seine Prioritätsebenen über beliebige natürliche Zahlen reichen, und sind in der Regel in 0-100), und Agda macht Sie erlauben Operatoren gleicher Priorität zu mischen , aber unterschiedliche fixities. Ich kann jedoch keine Informationen dazu in der Dokumentation finden, also musste ich experimentieren.
Lassen Sie uns unsere <@
und @>
von oben wiederverwenden . In den beiden einfachen Fällen haben wir
x <@ y @> z
Parsen als x <@ (y @> z)
; und
x @> y <@ z
Analyse als (x @> y) <@ z
.
Ich denke, was Agda tut, ist, die Zeile in "linksassoziative" und "rechtsassoziative" Blöcke zu gruppieren, und - wenn ich nicht über falsche Dinge nachdenke - erhält der rechtsassoziative Block "Priorität" beim Ergreifen der benachbarten Argumente. Das gibt uns also
a <@ b <@ c @> d @> e @> f <@ g
Analyse als
(((a <@ b) <@ (c @> (d @> (e @> f)))) <@ g
oder
Trotz meiner Experimente habe ich beim ersten Schreiben falsch geraten, was lehrreich sein könnte :-)
(Und Agda hat wie Haskell nicht assoziative Operatoren, die Analysefehler korrekt angeben, sodass gemischte Assoziativitäten auch zu einem Analysefehler führen können.)
Schließlich gibt es noch die Satzbeweis- / abhängig typisierte Sprache Coq , die eine noch flexiblere Syntax als Agda aufweist, da ihre Syntaxerweiterungen tatsächlich implementiert werden, indem Spezifikationen für die neuen syntaktischen Konstrukte angegeben und diese dann in die Kernsprache umgeschrieben werden (vage makroähnlich) , Schätze ich). In Coq ist die Listensyntax [1; 2; 3]
ein optionaler Import aus der Standardbibliothek. Neue Syntaxen können sogar Variablen binden!
Wiederum können wir in Coq unsere eigenen Infix-Operatoren definieren und ihnen Vorrangstufen (meistens von 0 bis 99) und Assoziativitäten zuweisen. In Coq kann jedoch jede Prioritätsstufe nur eine Assoziativität haben . Wenn wir also <@
als linksassoziativ definieren und dann versuchen, @>
auf derselben Ebene - sagen wir 50 - als rechtsassoziativ zu definieren , erhalten wir
Fehler: Level 50 ist bereits als linksassoziativ deklariert, während jetzt erwartet wird, dass es rechtsassoziativ ist
Die meisten Operatoren in Coq befinden sich auf Ebenen, die durch 10 teilbar sind. Wenn ich Assoziativitätsprobleme hatte (diese Assoziativitäten sind global), habe ich die Ebene im Allgemeinen nur um eins in beide Richtungen erhöht (normalerweise nach oben).