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.