开发者

How can I watch a subset of a clojure tree (Hash Map) for changes?

I would like to watch for changes to different parts of a Clojure Hash map (accessed via a STM ref), which forms quite a large tree, and on changes to those parts I would like to invoke some registered listeners. How can I do this in开发者_StackOverflow clojure as I understand that "add-watch" only works on an entire reference?


Since Clojure maps are immutable, there isn't really such a thing a a change to a single part of a tree from a conceptual perspective.

I can see a couple of good options however:

  • Add a watch to the entire tree, but test whether the particular part you are interested in has changed. This should be quite quick and easy to test (use "get-in" to look up the right part of the tree)
  • Marshall all changes to the tree through a library of helper functions, which can intercept the kind of changes you are interested in.


I, too, would watch the whole tree and check subsets with get-in. You can quickly test whether the subtree has been changed by using an identical? test against the previous state. Something like

(defn change-tester [tree path]
  (let [orig (get-in tree path)]
    (fn [tree]
      (not (identical? (get-in tree path) orig)))))

I don't use watchers very often so I don't know the syntax, but you could attach the above function somehow, I'm sure.


Clojure maps are immutable which means they are also thread safe which is a good thing. When you modify one with 'assoc' or similar you are creating a new copy in which your changed values are present. (Note that a full copy isn't made, but rather an efficient technique is employed to create a copy.)

I think perhaps the best way to do what you want is to create your own data structure, because essentially what you are asking for is a mutable HashMap as in Java, but not a Clojure Map.

You could create a wrapper around an existing Java HashMap which overrides the 'put' and 'putAll' methods so that you can detect what's being changed. If you have a HashMap within a HashMap you will want the sub HashMap to be of your new type as well so that you can detect changes at any level.

You might call it something like 'WatchfulHashMap'. Then, you will want to create an instance of this new HashMap like:

(def m (ref (WatchfulHashMap.)))

Thus making a single instance of it modifiable from anywhere in your app.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜