To start, suppose we are maintaining a set of pairs and we are interested in all triples [a b c] such that [a b] and [b c] are in our database. We define a function that prints such matches iff they are new since the function was last called:
(require '[comprehend :as c])
(require '[comprehend.mutable :as cm])
(defn report-new-matches [m-s]
"Prints new paths of length 3 since report-new-matches was last
called on m-s. Prints zero matches on the first invocation."
(let [!results (volatile! nil)]
(dosync
(vreset! !results (c/comprehend :mark :report-new-matches
@m-s
[a b]
[b c]
[a b c]))
(cm/mark m-s :report-new-matches))
(doseq [x @!results]
(println "Matched" x))))
This function runs a transaction that comprises two steps:- Run a query on the mutable indexed set
- Update the mutable indexed set with a marker
report-new-matches prints the results.We now hook up
report-new-matches as the 'io' argument of the mutable indexed set constructor:
(declare m-s) (defn live-reporter ([] nil) ([s diff] (report-new-matches m-s))) (def m-s (cm/mutable-indexed-set live-reporter)) (report-new-matches m-s) ; init(I admit the circular dependency between the definitions of
live-reporter and m-s is currently a little ugly. I might tweak the signature of 'io' functions to remedy this problem.)That's it! Let's see what happens when we add elements:
(reduce cm/conj m-s [[1 2] [2 3] [1 3] [3 4]]) ; Matched [1 3 4] ; Matched [1 2 3] ; Matched [2 3 4] (cm/conj m-s [0 1]) ; Matched [0 1 3] ; Matched [0 1 2]At some point the
comprehend.mutable API will be amended with a macro to make this even easier. In the meantime, as you can see, it's straightforward to role out your own solution.