Haskell: Definieren einer geeigneten Schnittstelle für Datentypen mit vielen Feldern

8

Für die Darstellung eines DSL-Syntaxbaums habe ich Datentypen, die diesen Baum repräsentieren. An mehreren Stellen bekomme ich innerhalb dieses Baumes eine ganze Reihe von Unterelementen, die optional sind und / oder eine "*" -Multiplizität haben. So könnte ein Datentyp etwa wie

aussehen %Vor%

Was ich suche, ist eine Möglichkeit, einen solchen Typ zu konstruieren, ohne alle Parameter angeben zu müssen, vorausgesetzt, dass ich für jeden von ihnen einen gültigen Standard habe. Das Verwendungsszenario ist derart, dass ich viele Instanzen des Typs mit allen Arten von Kombinationen seiner Parameter erzeugen oder auslassen muss (die meiste Zeit zwei oder drei), aber sehr selten alle von ihnen. Die Gruppierung der Parameter in Subtypen wird mich nicht weit bringen, da die Parameterkombinationen keinem Muster folgen, das eine Segmentierung verbessern würde.

Ich könnte Funktionen mit verschiedenen Parameterkombinationen definieren, um den Typ unter Verwendung von Standardeinstellungen für den Rest zu erstellen, aber ich könnte mit einer ganzen Anzahl von ihnen enden, die schwer zu benennen wären, da es keine Möglichkeit gibt, eine richtige zu geben Benennen Sie die Idee von createWithFirstAndThirdParameter in einem gegebenen Kontext.

Am Ende läuft die Frage also auf: Ist es möglich, einen solchen Datentyp oder eine Abstraktion darüber zu erzeugen, die mir so etwas wie optionale Parameter geben, die ich auf Wunsch spezifizieren oder weglassen kann?

    
Mathias Weyel 05.09.2013, 03:10
quelle

2 Antworten

11

Okay, ich werde meinen Kommentar erweitern. Definieren Sie zunächst Ihren Datentyp als Datensatz (und geben Sie einige Synonyme ein).

%Vor%

Als Nächstes erstellen Sie eine Standardinstanz

%Vor%

und wenn ein Benutzer ein Feld im Standard ändern möchte, um seine eigenen Daten zu erstellen, können sie dies tun:

%Vor%

Wenn sie zum Beispiel nur ein Element pattern wollen, können sie

verwenden %Vor%     
jozefg 05.09.2013, 04:31
quelle
12

Ich würde eine Kombination von Linsen und einer Standardinstanz vorschlagen. Wenn Sie Control.Lens nicht bereits in der Hälfte Ihrer Module importieren, sollten Sie jetzt beginnen! Was zum Teufel sind Linsen überhaupt? Ein Objektiv ist ein Getter und ein Setter, die zu einer Funktion zusammengefügt werden. Und sie sind sehr gut zusammensetzbar. Immer wenn Sie auf Teile einer Datenstruktur zugreifen oder diese ändern müssen, aber Sie denken, die Datensatzsyntax ist unhandlich, dann sind die Objektive für Sie da.

Also, das erste, was du tun musst - aktiviere TH und importiere Control.Lens .

%Vor%

Die Änderung, die Sie an Ihrem Datentyp vornehmen müssen, besteht darin, Namen für alle Felder hinzuzufügen:

%Vor%

Die Unterstriche am Anfang der Feldnamen sind wichtig für den nächsten Schritt. Weil wir jetzt Linsen für die Felder erzeugen wollen. Wir können GHC bitten, dies mit Template Haskell für uns zu tun.

%Vor%

Dann ist das letzte, was getan werden muss, eine "leere" Instanz zu konstruieren. Achten Sie darauf, dass niemand statisch überprüft, dass Sie tatsächlich alle erforderlichen Felder ausfüllen. Daher sollten Sie diesen Feldern vorzugsweise error hinzufügen, damit Sie zumindest einen Laufzeitfehler erhalten. Etwas wie das:

%Vor%

Jetzt sind Sie bereit zu rollen! Sie können ein emptyExpression nicht verwenden und es wird zur Laufzeit fehlschlagen:

%Vor%

Aber! Solange Sie das Typenfeld ausfüllen, sind Sie golden:

%Vor%

Sie können auch mehrere Felder gleichzeitig ausfüllen, wenn Sie möchten.

%Vor%

Sie können auch Linsen verwenden, um eine Funktion auf ein Feld anzuwenden oder in ein Feld eines Felds zu schauen oder einen anderen vorhandenen Ausdruck usw. zu ändern. Ich empfehle auf jeden Fall, einen Blick darauf zu werfen, was Sie tun können!

    
kqr 05.09.2013 04:53
quelle

Tags und Links