Erkundung der Idee, dass typeclasses im Wesentlichen C ++ - abstrakte Klassen ohne verschachtelte Vererbung sind , ich habe die typeclass geschrieben
%Vor%Mit einer Schnittstelle wie
%Vor%Ich hätte gerne etwas wie
%Vor%Damit ich
machen konnte %Vor% Während type IDrawable c
mit ConstraintKinds
kompiliert wird, darf ich instance IDrawable Object where i = IDrawable . objectDraw
nicht mit dem Fehler
Gibt es eine Möglichkeit, IDrawable c = Interface IDrawable' c
so zu deklarieren, dass es instanziert werden kann?
Das ist rein aus akademischem Interesse, ich empfehle niemanden, dieses Muster in einer echten Anwendung zu verwenden. Ich möchte nur wissen, ob das möglich ist, ohne TemplateHaskell
oder CPP
anzuwenden.
Nein, das ist nicht möglich (ab 7.8.3, und ich denke auch 7.10); Es ist GHC-Fehler # 7543 . Es ist kein sehr gehandelter Bug; Es gibt eindeutig mindestens ein paar Leute, die diese Art von Dingen gerne schreiben würden ( z. B. , du, Edward Kmett), aber meistens bleibt das unbemerkt. Es gibt keinen Fortschritt beim Ändern dieses Verhaltens, das im Tracker aufgezeichnet wurde.
Warum können Sie nicht, lassen Sie mich Simon Peyton-Jones Erklärung auf dem Bug-Tracker paraphrasieren. Das Problem besteht darin, dass Typprüfungsinstanzen aus zwei Teilen bestehen: Zuerst muss GHC nachschlagen, wo die Methodennamen (hier, i
) herkommen; Zweitens muss GHC die Typensynonyme erweitern. Da diese beiden Schritte in diesem Problem von zwei verschiedenen Komponenten von GHC ausgeführt werden, können Constraint-Synonym-Instanzen nicht unterstützt werden. GHC kann nicht feststellen, in welcher Klasse gesucht werden muss, um i
zu finden.
Der andere Grund dafür ist ein Fehler - und der Grund, warum ich das gefunden habe, laut den Kommentaren zu András Kovács 'Antwort - ist das aktuelle Verhalten nicht so einfach wie "es funktioniert nicht". Stattdessen versucht zu arbeiten, aber Sie können keine Methoden deklarieren ... aber Sie können eine methodenlose Instanz deklarieren! In GHCi:
%Vor%Mit anderen Worten:
%Vor%schlägt fehl, aber
%Vor%ist erfolgreich! So muss der Check je nach gewünschtem Verhalten entweder gelockert oder gestrafft werden: -)
S.S .: Noch eine Sache: Sie sollten Typ Synonyme immer so weit wie möglich reduzieren. Deshalb habe ich IDrawable
auf
und den Parameter c
auf beiden Seiten im obigen Code GHCi
entfernt. Der Vorteil besteht darin, dass Typ-Synonyme nicht teilweise angewendet werden können. Daher können Sie Ihre Version von IDrawable
nicht als Parameter an irgendetwas übergeben. jedoch kann die voll eta-reduzierte Version irgendwo mit etwas Art * -> Constraint
erwartet werden.
(Dies wird in András Kovács 'Antwort angesprochen, und ich erwähnte dies in einem Kommentar dort, dennoch, seit ich endete auch eine Antwort zu schreiben, ich dachte, ich würde es auch hier hinzufügen.)
Sie können eine "partielle" Klasse ohne Instanzen deklarieren:
%Vor%Alternativ können Constraint-Synonyme verwendet werden:
%Vor% Die klassische Lösung ist wahrscheinlich vorzuziehen, da die Klasse IDrawable
eine richtige * -> Constraint
Art hat, während das Synonym des Typs unbrauchbar ist, wenn sie nicht vollständig angewendet wird. Dies kann relevant sein, da Datendefinitionen (und Typfamilien und so gut wie alle Arten von Hacker-Typen) nur die richtigen Typkonstruktoren verwenden können.