1 #+TITLE: Concurrent Propagator System
2 #+OPTIONS: num:nil ^:nil
7 :tangle: src/propagator.clj
12 #^{:author "Eric Schulte",
14 :doc "Simple concurrent propagator system."}
16 (:use clojure.contrib.repl-utils))
18 (defmacro cell "Define a new cell."
20 `(def ~name (agent ~state)))
22 (defmacro propagator "Define a new propagator."
23 [name in-cells out-cells & body]
25 (defn ~(with-meta name
27 :in-cells in-cells :out-cells out-cells))
29 (doseq [cell# ~in-cells] (add-neighbor cell# ~name))
32 (defmacro run-propagator
33 "Run a propagator, first collect the most recent values from all
34 cells associated with the propagator, then evaluate."
36 `(let [run-me# (fn [_#]
37 (apply ~propagator (map deref (:in-cells ^#'~propagator))))]
38 (map (fn [cell#] (send cell# run-me#)) (:out-cells ^#'~propagator))))
40 (defmacro add-neighbor "Add a neighbor to the given cell."
44 (agent nil :validator (fn [_#] (do (future (run-propagator ~neighbor)) true)))
49 ** look at mutable data stores
50 - http://clojure.org/agents
51 - http://clojure.org/atoms
52 - http://clojure.org/refs
54 most definitely will use agents, functions to set their values are
55 applied to them with send (or send-off if potentially I/O bound), they
56 support validators, and they can be set to run actions (i.e. alert
57 propagators) as part of their update cycle.
59 ** design to permit distribution across multiple machines
60 it should be possible to wrap these mutable items including
61 - network connections from other machines
62 - hardware (timers, I/O devices, etc...)
64 in cells, so that the propagator system remains "pure"
67 This probably mentioned a request for advice from the mailing list or
68 from the #clojure group.