Transformiere eine Funktion mit einer Typklassenbeschränkung in eine Funktion, die ein explizites Typklassenwörterbuch verwendet

8

Es ist allgemein bekannt, dass eine Art der Implementierung von Haskell-Typklassen über Typklassenwörterbücher erfolgt. (Dies ist natürlich die Implementierung in ghc, obwohl ich die obligatorische Bemerkung mache, dass andere Implementierungen möglich sind.) Um Ideen zu fixieren, beschreibe ich kurz, wie das funktioniert. Eine Klassendeklaration wie

%Vor%

kann mechanisch in die Definition eines Datentyps wie:

umgewandelt werden %Vor%

Dann können wir jede Instanzdeklaration mechanisch in ein Objekt dieses Typs transformieren; zum Beispiel:

%Vor%

wird zu

%Vor%

und ähnlich kann eine Funktion, die eine Typklassenbeschränkung hat, in eine Funktion umgewandelt werden, die ein zusätzliches Argument benötigt; zum Beispiel:

%Vor%

wird zu

%Vor%

Der Punkt ist, solange der Compiler weiß, wie man diese versteckten Argumente ausfüllt (was nicht ganz trivial ist), können Sie Code, der Klassen und Instanzen verwendet, in Code übersetzen, der nur mehr Grundfunktionen der Sprache verwendet / p>

Mit diesem Hintergrund, hier ist meine Frage. Ich habe ein Modul M , das eine Menge von Klassen und Funktionen mit Klassenbeschränkungen definiert. M ist 'undurchsichtig'; Ich kann sehen, was es exportiert (das Äquivalent der .hi-Datei), und ich kann es importieren, aber ich kann seinen Quellcode nicht sehen. Ich möchte ein neues Modul N konstruieren, das im Grunde die gleichen Dinge exportiert, aber mit der oben angegebenen Transformation. Also zum Beispiel wenn M exportiert

%Vor%

N würde wie

beginnen %Vor%

Und meine Frage ist Was um alles in der Welt kann ich an Stelle des ??? setzen. Mit anderen Worten: Was kann ich schreiben, um die 'explicit typeclass' Version der Funktion my_fn aus dem Original zu extrahieren? Es erscheint ziemlich schwierig, und es ist ärgerlich, weil wir alle wissen, dass das Modul M im Grunde bereits etwas exportiert, wie das my_fn_ , das ich erstellen möchte. (Oder zumindest ist es auf GHC.)

    
circular-ruin 03.03.2014, 22:16
quelle

3 Antworten

2

Für die Aufzeichnung dachte ich, ich würde die "Hacky" -Lösung für das, was ich bereits kenne, erklären. Ich werde es anhand einer Reihe von Beispielen illustrieren. Stellen wir uns also vor, wir versuchen, die Klassen, Instanzen und Funktionen im Folgenden zu vereinheitlichen (die hauptsächlich aus hübschen Standard-Typklassen bestehen, die für die Darstellung allgemein etwas vereinfacht sind):

%Vor%

In diesen Beispielen soll etwas Allgemeinheit sein: Wir haben

  • 'a' in positiver Position im Klassenmitglied
  • 'a' in negativer Position im Klassenmitglied
  • eine Instanz, die flexible Instanzen erfordert
  • ein höherer Typ

Wir verlassen Multiparameterfamilien als Übung! Beachten Sie, dass ich glaube, dass das, was ich vorstelle, ein völlig allgemeines, syntaktisches Verfahren ist; Ich denke nur, dass es einfacher ist, Beispiele zu illustrieren, als die Transformation formell zu beschreiben. Nehmen wir an, wir haben die folgenden Funktionen zur Verarbeitung:

%Vor%

Dann sieht die tatsächliche Verdinglichung wie folgt aus:

%Vor%

Beachten Sie, dass wir eine Menge von unsafeCoerce verwenden, aber immer zwei Typen betreffen, die sich nur durch das Vorhandensein eines neuen Typs unterscheiden. Da die Laufzeitdarstellungen identisch sind, ist dies in Ordnung.

    
circular-ruin 04.03.2014, 22:17
quelle
1

Was Sie zu fragen scheinen, wird als "lokale Instanzen" bezeichnet. Dies würde bedeuten, dass Sie etwas schreiben könnten wie:

%Vor%

Lokale Instanzen sind eine natürliche Erweiterung von Typklassen. Sie waren sogar Standard im Formalismus von Wadler und Blott's Papier "Wie man Ad-hoc-Polymorphismus weniger ad hoc macht". Sie sind jedoch problematisch, da sie eine Eigenschaft, die als Haupttypen bezeichnet wird, auflösen. Darüber hinaus können sie auch Annahmen brechen, dass es immer nur eine einzige Instanz einer bestimmten Einschränkung für einen bestimmten Typ gibt (wie beispielsweise die Annahme von Data.Map über Ord-Instanzen). Das erste Problem könnte gelöst werden, indem zusätzliche Typ-Annotationen in einer lokalen Instanz benötigt werden und das letztere Problem mit den umstrittenen "verwaisten Instanzen" zusammenhängt, die ein ähnliches Problem verursachen.

Ein weiteres relevantes Papier ist Kisselyov und Shans "Functional pearl: Implizite Konfigurationen", das eine Vielzahl von Typsystem-Tricks enthält, um Instanzen des lokalen Typs zu simulieren, obwohl es nicht wirklich auf Ihre Situation zutrifft (vorbestehende Typklasse), IIRC .

    
Dominique Devriese 04.03.2014 07:28
quelle
0

Dies ist im Allgemeinen keine Lösung, sondern nur für einige Spezialfälle.

Es gibt einen heiklen Weg, dies für Klassenmethoden von class C t zu tun, bei denen der Typ-Parameter t in ihrem Typ in einer negativen Position erscheint. z. B. example1 :: Foo t => t -> t -> t ist in Ordnung, aber nicht example2 :: Foo t => t .

Der Trick besteht darin, einen Wrapperdatentyp Wrapper t zu erstellen, der die expliziten Dictionary-Methoden auf t gepaart mit einem t -Wert enthält und eine Foo -Instanz besitzt, die die entsprechenden Wrapped-Dictionary-Methoden ausnutzt, z

%Vor%

Etwas sagt mir, dass dies wahrscheinlich nicht die Lösung ist, nach der Sie suchen, aber es ist kein allgemeiner Zweck. Im Beispiel hier können wir nichts mit example2 machen, weil es kein negatives Vorkommen von t gibt, mit dem man Funktionen "schleichen" kann. Für Ihr Beispiel bedeutet dies, dass my_fn in Modul M nur example1 verwenden kann.

    
dorchard 04.03.2014 00:06
quelle

Tags und Links