2017-10-16 19 views
2

Comment puis-je définir un nouvel enregistrement qui "hérite" les protocoles d'un type existant?Comment transmettre les méthodes de protocole au type existant?

Pour rendre cette question claire, je vais illustrer avec extension Ubergraph, mais Ubergraph est seulement un exemple; Je cherche la solution générale, pas seulement une solution qui fonctionne pour Ubergraph. Supposons que je souhaite ajouter un attribut global, graph-name, à Ubergraph. Idéalement, je pouvais faire quelque chose comme ceci:

(defrecord named-ubergraph [g graph-name]) 

(extend-type named-ubergraph 
    (all-the-protocols-supported-by ubergraph.core.Ubergraph) 
    (call-the-same-functions-replacing-first-argument-with '(this g)) 

Bien sûr, je pouvais regarder le code source Ubergraph et écrire manuellement toutes les fonctions de transfert, mais as you can see here, Ubergraph satisfait beaucoup protocoles et beaucoup méthodes de protocole. Écrire autant de code standard n'a pas l'air très clojurely, et il semble que beaucoup de travail quand tout ce que je veux faire est d'ajouter un peu de données à un Ubergraph. Quoi de mieux?

S'il vous plaît n'hésitez pas à reconceptualiser la question si vous pensez que je regarde ce problème.

Répondre

1

extend-type étend les types existants à des protocoles donnés. Si je vous comprends bien, vous voulez étendre l'enregistrement existant pour obtenir une sorte d'héritage. AFAIK, il n'y a pas de moyen facile de le faire. Cependant, si tout ce que vous voulez est d'ajouter un autre champ, vous pouvez facilement assoc champ supplémentaire à une instance d'enregistrement existant:

(defprotocol Cost 
    (cost [this price-list])) 

(defrecord Car [name speed] 
    Cost 
    (cost [this price-list] (price-list (:name this)))) 

(def my-car (->Car "bmw" 200)) 
(def price-list {"bmw" 100000}) 

(cost my-car price-list) 
;;=> 100000 

(-> my-car 
    (assoc :color "blue") 
    (cost price-list)) 
;;=> 100000 

MISE À JOUR: J'ai aussi trouvé cette discussion fantastique sur la liste de diffusion Clojure: defrecord avec "héritage": https://groups.google.com/forum/#!topic/clojure/mr-o9sRyiZ0

+0

Juste 'assoc'-ing à l'enregistrement est un bon aperçu! Je savais que Clojure le permettait, mais je n'y avais pas pensé à propos de ce problème. Cela résout instantanément beaucoup de mes problèmes actuels - avec la quantité idéale de code: aucun! Cependant, j'ai juste essayé d'associer à un Ubergraph, et cela ne fonctionne pas. Donc, je laisse la question ouverte pour le moment. (Ajouter des données arbitraires à un Ubergraph _is_ est en fait la principale raison pratique pour laquelle j'ai besoin de cela maintenant.) –

+0

Hmm, Ubergraph a même [les déclarations de cas] (https://github.com/Engelberg/ubergraph/blob/320e284a6de6adb241df5dfeb9fd6383caea659c/src/ ubergraph/core.clj # L214) qui empêche 'assoc'-ing à des clés arbitraires. –