2010-06-24 5 views
14

Ich entwickle eine komplexe Datenstruktur in Clojure mit mehreren Unterstrukturen.Abstraktion von Datenstrukturimplementierungsdetails in Clojure

Ich weiß, dass ich diese Struktur im Laufe der Zeit erweitern möchte und manchmal die interne Struktur ändern möchte, ohne verschiedene Benutzer der Datenstruktur zu brechen (zum Beispiel möchte ich vielleicht einen Vektor in eine Hashmap ändern, addieren eine Art von Indexstruktur aus Leistungsgründen oder ein Java-Typ) integrieren

Mein aktuelles Denken ist:

  • ein Protokoll mit Methoden verschiedenen Accessor für die Gesamtstruktur definieren
  • eine Mini-Bibliothek erstellen von Funktionen, die durch die Datenstruktur navigieren e .G. (Abfrage-Unterbau-abc param1 param2)
  • Implementieren Sie die Datenstruktur unter Verwendung defrecord oder Deftype, mit den Protokoll Methoden definiert, um die Mini-Bibliothek verwenden

Ich denke, das wird funktionieren, aber ich mache mir Sorgen, es fängt an, wie ziemlich viel "Kleber" Code auszusehen. Wahrscheinlich spiegelt es auch meine größere Vertrautheit mit objektorientierten Ansätzen wider.

Was ist der empfohlene Weg, dies in Clojure zu tun?

Antwort

11

Ich denke, dass deftype könnte der Weg zu gehen, aber ich würde einen Pass auf die Accessor-Methoden. Schauen Sie stattdessen in clojure.lang.ILookup und clojure.lang.Associative; Dies sind Schnittstellen, die Sie, wenn Sie sie für Ihren Typ implementieren, verwenden können get/get-in und assoc/assoc-in, was für eine viel vielseitigere Lösung (nicht nur werden Sie in der Lage sein, die zugrunde liegende Implementierung zu ändern, sondern vielleicht auch zu verwenden Funktionen, die auf der Standardbibliothek von Clojure basieren, um Ihre Strukturen zu manipulieren).

Ein paar Dinge zu beachten:

  1. Sie wahrscheinlich mit defrecord, mit get, assoc & Co. mit dem Standard defrecord Implementierungen von ILookup, Associative, IPersistentMap und java.util.Map beginnen sollen. Sie könnten einen ziemlich langen Weg damit gehen.

    Wenn/wenn diese nicht mehr ausreichen, sehen Sie sich die Quellen für emit-defrecord an (eine private Funktion, die in core_deftype.clj in Clojures Quellen definiert ist). Es ist ziemlich komplex, aber es gibt Ihnen eine Vorstellung davon, was Sie möglicherweise implementieren müssen.

  2. Weder deftype noch defrecord definieren derzeit irgendwelche Factory-Funktionen für Sie, aber Sie sollten es wahrscheinlich selbst tun. In diese Funktionen (und/oder die entsprechenden Tests) geht die Überprüfung der Gesundheit.

  3. Je mehr konzeptionell komplexe Vorgänge sind natürlich eine perfekte Passform für Protokoll auf der Grundlage von get & Co.

Oh gebaut Funktionen und haben einen Blick auf gvec.clj in Quellen Clojure ist ein Beispiel für wie könnte ein seriöser Datenstrukturcode aussehen, der unter Verwendung von deftype geschrieben wurde.Die Komplexität hier ist von einer anderen Art als die, die Sie in der Frage beschreiben, aber dennoch ist es eines der wenigen Beispiele für benutzerdefinierte Datenstrukturprogrammierung in Clojure, die derzeit für den öffentlichen Verbrauch verfügbar sind (und es ist natürlich ein ausgezeichneter Qualitätscode).

Natürlich ist das genau das, was mir meine Intuition zu dieser Zeit sagt. Ich bin mir nicht sicher, ob es in diesem Stadium viel etablierte Idiome gibt, was mit deftype nicht wirklich freigegeben wurde und alle. :-)

+0

Danke Michal! Insightful wie immer :-) wird definitiv in die ILookup und Assoziative Optionen – mikera

+0

Dies ist eine sehr nützliche Antwort! Aber fast drei Jahre später wäre es großartig, dies zu aktualisieren (oder eine neue Antwort zu erstellen), basierend auf der Funktion, die jetzt in 1.5 verfügbar ist. Eine Sache, die mir aufgefallen ist, ist, dass "Defrecord" jetzt Factory-Funktionen ausstrahlt, nicht sicher, welche anderen Änderungen diese Antwort beeinflussen könnten. –

+0

Ich denke, diese Antwort könnte auch ein Update verwenden - selbst das O'Reily Clojure-Buch sagt nun, dass clojures Defrecord Factory-Funktionen erzeugt. – djhaskin987