2010-06-24 22 views
14

Je développe une structure de données complexe dans Clojure avec plusieurs sous-structures. Je sais que je vais vouloir étendre cette structure au fil du temps, et peut parfois vouloir changer la structure interne sans casser les différents utilisateurs de la structure de données (par exemple je peux vouloir changer un vecteur dans un hashmap, ajouter une sorte de structure d'indexation pour des raisons de performance, ou intégrer un type Java)Résumé des détails de mise en œuvre de la structure de données dans Clojure

Ma pensée actuelle est:

  • Définir un protocole pour la structure globale avec différentes méthodes accesseurs
  • Créer une mini-bibliothèque de fonctions qui naviguent dans la structure de données e .g. (Param1 param2 requête sous-structure-abc)
  • Mettre en œuvre la structure de données à l'aide defrecord ou DEFTYPE, avec les méthodes de protocole définies pour utiliser la mini-bibliothèque

Je pense que cela va fonctionner, mais je suis inquiet qu'il commence à ressembler plutôt à beaucoup de code "colle". Aussi, cela reflète probablement aussi ma plus grande familiarité avec les approches orientées objet.

Quelle est la méthode recommandée pour faire cela dans Clojure?

Répondre

11

Je pense que deftype pourrait être la voie à suivre, mais je prendrais un laissez-passer sur les méthodes d'accesseur. Au lieu de cela, regardez clojure.lang.ILookup et clojure.lang.Associative; ce sont des interfaces qui, si vous les implémentez pour votre type, vous permettront d'utiliser get/get-in et assoc/assoc-in, ce qui rendra la solution beaucoup plus polyvalente (non seulement vous serez en mesure de changer l'implémentation sous-jacente, mais peut-être aussi d'utiliser fonctions construites au-dessus de la bibliothèque de collections standard de Clojure pour manipuler vos structures).

Un couple de choses à noter:

  1. Vous devriez probablement commencer par defrecord, en utilisant get, assoc & Co. avec les standards defrecord implémentations de ILookup, Associative, IPersistentMap et java.util.Map. Vous pourriez peut-être aller assez loin avec cela.

    Si cela ne suffit plus, jetez un oeil aux sources pour emit-defrecord (une fonction privée définie dans core_deftype.clj dans les sources de Clojure). C'est assez complexe, mais cela vous donnera une idée de ce que vous pourriez avoir besoin de mettre en œuvre.

  2. Ni deftype ni defrecord ne définissent actuellement des fonctions d'usine pour vous, mais vous devriez probablement le faire vous-même. La vérification de la santé va dans ces fonctions (et/ou les tests correspondants).

  3. plus les opérations sur le plan conceptuel complexe sont bien sûr un ajustement parfait pour les fonctions de protocole construit sur la base de get & Co.

Oh, et jeter un oeil à gvec.clj dans les sources de Clojure pour un exemple de Ce que pourrait être un code de structure de données sérieuse écrit en utilisant deftype.La complexité ici est d'un genre différent de ce que vous décrivez dans la question, mais c'est quand même l'un des rares exemples de programmation de structures de données personnalisées dans Clojure actuellement disponible pour la consommation publique (et c'est bien sûr un excellent code qualité).

Bien sûr, c'est exactement ce que me dit mon intuition en ce moment. Je ne suis pas sûr qu'il y ait beaucoup d'idiomes établis à ce stade, ce qui avec deftype n'a pas vraiment été publié et tout. :-)

+0

Merci Michal! Insightful comme jamais :-) va certainement regarder dans les options ILookup et Associative – mikera

+0

Ceci est une réponse très utile! Mais près de trois ans plus tard, il serait bon de mettre à jour ceci (ou de créer une nouvelle réponse) en fonction de la fonctionnalité disponible en 1.5. Une chose que j'ai remarquée est que 'defrecord' émet maintenant des fonctions d'usine, pas sûr que d'autres changements pourraient affecter cette réponse. –

+0

Je pense que cette réponse pourrait aussi utiliser une mise à jour - même le livre O'Reily Clojure dit maintenant que le defrecord de clojure crée des fonctions d'usine. – djhaskin987