1 (ns #^{:author "Eric Schulte",
3 :doc "Simple concurrent propagator system."}
5 (:use clojure.contrib.repl-utils clojure.contrib.math))
7 (defn set-cell "Set the value of a cell" [cell value]
8 (send cell (constantly value)))
10 (defmacro run-propagator
11 "Run a propagator, first collect the most recent values from all
12 cells associated with the propagator, then evaluate."
14 `(let [results# (apply ~propagator (map deref (:in-cells (meta ~propagator))))]
15 (doseq [cell# (:out-cells (meta ~propagator))]
16 (when (not (= @cell# results#))
17 (set-cell cell# results#)))
20 (defn add-neighbor "Add a neighbor to the given cell." [cell neighbor]
21 (add-watch cell nil (fn [_ _ _ _] (future (run-propagator neighbor)))))
23 (defmacro defcell "Define a new cell." [name state]
24 `(def ~name (agent ~state)))
26 (defmacro defpropagator "Define a new propagator."
27 [name in-cells out-cells & body]
28 `(let [v# (defn ~(vary-meta name assoc :in-cells in-cells :out-cells out-cells)
30 (doseq [cell# ~in-cells] (add-neighbor cell# ~name))