views:

124

answers:

1

Clojure's system for creating an ad hoc hierarchy of keywords is familiar to most people who have spent a bit of time with the language. For example, most demos and presentations of the language include examples such as

(derive ::child ::parent)

and they go on to show how this can be used for multi-method dispatch.

In all of the slides and presentations that I've seen, they use the global hierarchy. But it is possible to put keyword relationships in independent hierarchies, by using (derive h ::child ::parent), where h is created by (make-hierarchy). Some questions, therefore:

  • Are there any guidelines on when this is useful or necessary?
  • Are there any functions for manipulating hierarchies?

Merging is particularly useful, so I do this:

(defn merge-h [& hierarchies] 
   (apply merge-with (cons #(merge-with clojure.set/union %1 %2) hierarchies))

But I was wondering if such functions already exist somewhere.

EDIT: Changed "custom" hierarchy to "independent" hierarchy, since that term better describes this animal. Also, I've done some research and included my own answer below. Further comments are welcome.

+3  A: 

I've delved into this problem over the last few days, and I think I have some answers:

  1. Functions used on independent hierarchies have different semantics from when the same functions are used on the global hierarchy. Doing (derive kwd1 kwd2) produces a side-effect -- an entry in the global hierarchy. On the other hand, (derive hierarchy kwd1 kwd2) is functional -- the function returns a new hierarchy, instead of modifying a var.
  2. Using independent hierarchies allows you to have several different hierarchies for the same keywords. So for instance:

    (def basketball-hierarchy (derive (make-hierarchy) :gretzky :jordan))

    (def hockey-hierarchy (derive (make-hierarchy) :jordan :gretzky))

Could indicate that :jordan is higher in the basketball hierarchy than :gretzky, whereas the reverse is true in the hockey hierarchy.

Also: non-namespaced keywords can be put into independent hierarchies, but not into the global hierarchy. So

(derive (make-hierarchy) :a :b)

will work, but for the global hierarchy, these keywords would have to be in a namespace:

(derive :nspace/a :nspace/b)

where nspace is some namespace. (This namespace does not actually have to be declared anywhere, interestingly.)

In summary, then, independent hierarchies should be used when more than one hierarchy is needed, or when the hierarchy needs to be modified extensively during run time. Also, if we want a hierarchy for naked keywords, an independent hierarchy is required.

Rob Lachlan