Wie schränkt man in Haskell Funktionen auf nur einen Konstruktor eines Datentyps ein?

8

Ich bin mir nicht sicher, wie ich diese Frage formulieren soll. Angenommen, ich versuche, die Pfade von tmpfiles herumzugeben, und ich möchte die Idee einfangen, dass es verschiedene Formate von tmpfile gibt und jede Funktion nur auf einem von ihnen funktioniert. Das funktioniert:

%Vor%

Aber es muss einen besseren Weg geben, es ohne Laufzeitfehler zu schreiben, oder? Ich dachte über zwei Alternativen nach:

%Vor%

Oder das:

%Vor%

Aber offensichtlich kompilieren sie nicht. Was ist der richtige Weg, es zu tun? Einige andere Ideen, keine besonders ansprechend:

  • Wickeln Sie TmpFile in das Format anstatt umgekehrt, also sind die Werte Video (TmpFile "test.avi") etc.
  • Erstellen Sie viele separate Datentypen VideoTmpFile , PictureTmpFile etc.
  • Machen Sie eine TmpFile typeclass
  • Verwenden Sie Teilfunktionen überall, aber fügen Sie Schutzfunktionen hinzu, um die Mustererkennung
  • zu abstrahieren

Ich habe auch überlegt, die Erweiterung -XDataKinds zu lernen, aber ich vermute, dass mir etwas viel Einfacheres fehlt, das ohne es möglich ist.

EDIT: Ich lerne heute viel! Ich probierte beide Ansätze aus ( DataKinds und Phantom-Typen, die Dummy-Wert-Konstruktoren haben, die mit einer anderen Erweiterung entfernt werden können), und beide funktionieren! Dann habe ich versucht, etwas weiter zu gehen. Sie lassen Sie beide einen verschachtelten Typ TmpFile (ListOf a) zusätzlich zu regulären TmpFile a erstellen, was cool ist. Aber ich habe vorläufig entschieden, mit einfachen Phantom-Typen (intact-Wert-Konstruktoren) zu gehen, weil Sie auf ihnen eine Muster-Übereinstimmung finden können. Zum Beispiel war ich überrascht, dass das tatsächlich funktioniert:

%Vor%

Soweit ich das beurteilen kann, ist das Äquivalent mit DataKinds sehr ähnlich, aber kann nicht auf fmt als Wert zugreifen:

%Vor%

(Es mag wie eine seltsame Sache zu wollen scheinen, aber mein aktuelles Programm wird ein Interpreter für eine kleine Sprache sein, die Shake-Regeln mit einer tmpfile entsprechend jeder Variablen kompiliert, so dass getippte Listen von tmpfiles nützlich sein werden)

Scheint das richtig? Ich mag die Idee von DataKinds besser, also würde ich stattdessen mitgehen, wenn ich sie als Werte untersuchen könnte, oder wenn es sich herausstellt, dass das nie nötig ist.

    
Jeff 08.02.2016, 20:53
quelle

2 Antworten

5

Sie haben Recht: Mit -XDataKinds würde der Ansatz TmpFile Video -> FilePath funktionieren. Und tatsächlich denke ich, dass dies eine gute Anwendung für diese Erweiterung sein könnte.

%Vor%

Der Grund, warum Sie diese Erweiterung zum Schreiben von TmpFile Video benötigen, ist, dass die Konstruktoren von FileFormat ab initio value-level sind (also nur zur Laufzeit existieren), während TmpFile type- Level / Kompilierzeit.

Natürlich gibt es eine andere Möglichkeit, Entitäten auf Typenebene zu generieren: Typen definieren !

%Vor%

Solche Typen werden Phantomtypen genannt. Aber wirklich, sie sind ein bisschen wie ein Hack, um das frühere Fehlen von richtigen Typenwerten zu umgehen, die DataKinds uns jetzt gegeben hat. Wenn Sie also keine Kompatibilität mit alten Compilern benötigen, verwenden Sie DataKinds!

Eine Alternative wäre, nicht den Dateityp zum Zeitpunkt der Kompilierung zu erzwingen, sondern einfach zu verdeutlichen, dass die Funktionen partiell sind.

%Vor%

Tatsächlich könnte dieser Ansatz der rationellere sein, je nachdem, was Sie vorhaben.

    
leftaroundabout 08.02.2016, 21:12
quelle
2

Zunächst würde ich davon abraten, solche exotischen Erweiterungen wie "DataKinds" zu verwenden, wenn Sie sie nicht unbedingt brauchen. Der Grund ist ziemlich praktisch und allgemein: je mehr Sprachkonzepte Sie verwenden, um Ihr Problem zu lösen, desto schwieriger ist es, über Ihren Code nachzudenken.

Außerdem ist "DataKinds" kein einfaches Konzept, um den Kopf zu verdrehen. Es ist ein Übergangskonzept, das zwei Universen gleichzeitig durchquert: die Werte und die Typen. Ich persönlich finde es ziemlich umstritten und würde es nur anwenden, wenn ich keine andere Möglichkeit habe.

In Ihrem Fall haben Sie bereits zwei Wege gefunden, Ihr Problem einfacher anzugehen, ohne "DataKinds":

  
  • Wrap Tmpfile im Format anstatt umgekehrt, also sind die Werte Video (TmpFile "test.avi") etc.

  •   
  • Erstellen Sie viele separate Datentypen, VideoTmpfile, PictureTmpfile usw.

  •   

Ich mag besonders die Idee der Verpackungsarten, weil sie flexibel und zusammensetzbar ist. Hier ist, wie ich darauf aufbauen würde:

%Vor%

Sie können zwei Dinge bemerken:

  1. Video und Picture sind allgemeine Konzepte, die nicht nur an Ihre temporären Dateien gebunden sind und bereits einige Standardschnittstellen implementieren. Dies bedeutet, dass sie für andere Zwecke wiederverwendet werden können.

  2. Es gibt ein offensichtliches Muster in den Definitionen von Video und Picture .

Das Muster, das Sie in Video und Picture sehen, kann als "Verfeinerungstypen" bezeichnet werden und wird in der "raffiniertes" Paket unter anderem. Das könnte dich interessieren.

Wie für Ihre anderen Optionen:

  
  • Erstellen Sie eine TmpFile-Typklasse

  •   
  • Verwenden Sie Teilfunktionen überall, aber fügen Sie Schutzfunktionen hinzu, um die Mustererkennung zu abstrahieren

  •   

Das ist ein definitives "Nein" zu beiden. Züchte keine Typklassen, lass sie für die wirklich allgemeinen Konzepte sein, die Gesetze und wahrscheinlich eine (Kategorien-) Theorie hinter sich haben. Die Sprache bietet Ihnen viele weitere Möglichkeiten zur Abstraktion. Lassen Sie auch keine Teilfunktionen zu Ihren APIs crawlen - es gibt einen Konsens in der Community, dass es sich um ein Antipattern handelt.

    
Nikita Volkov 09.02.2016 08:13
quelle

Tags und Links