1 #+TITLE: Concurrent Propagator System
2 #+OPTIONS: num:nil ^:nil
7 :tangle: src/propagator.clj
11 #^{:author "Eric Schulte",
13 :doc "Simple concurrent propagator system."}
15 (:use clojure.contrib.repl-utils clojure.contrib.math))
17 (defmacro cell "Define a new cell."
19 `(def ~name (agent ~state)))
21 (defmacro propagator "Define a new propagator."
22 [name in-cells out-cells & body]
24 (defn ~(with-meta name
26 :in-cells in-cells :out-cells out-cells))
28 (doseq [cell# ~in-cells] (add-neighbor cell# ~name))
31 (defn set-cell "Set the value of a cell" [cell value]
32 (send cell (fn [_] value)))
34 (defmacro run-propagator
35 "Run a propagator, first collect the most recent values from all
36 cells associated with the propagator, then evaluate."
38 `(let [results# (apply ~propagator (map deref (:in-cells ^#'~propagator)))]
39 (doseq [cell# (:out-cells ^#'~propagator)]
40 (when (not (= @cell# results#))
41 (send cell# (fn [_#] results#))))
44 (defmacro add-neighbor "Add a neighbor to the given cell."
48 (agent nil :validator (fn [_#] (do (future (run-propagator ~neighbor)) true)))
52 ** doubling a number -- simplest
56 (propagator doubler [in] [out] (* 2 in))
57 ;; then any updates to in
59 ;; will propagate to out
63 ** square roots -- heron
72 (propagator enough [x guess] [done]
73 (if (< (abs (- (* guess guess) x)) @margin) true false))
75 (propagator heron [x guess] [guess]
78 (/ (+ guess (/ x guess)) 2.0)))
82 ** look at mutable data stores
83 - http://clojure.org/agents
84 - http://clojure.org/atoms
85 - http://clojure.org/refs
87 most definitely will use agents, functions to set their values are
88 applied to them with send (or send-off if potentially I/O bound), they
89 support validators, and they can be set to run actions (i.e. alert
90 propagators) as part of their update cycle.
92 ** design to permit distribution across multiple machines
93 it should be possible to wrap these mutable items including
94 - network connections from other machines
95 - hardware (timers, I/O devices, etc...)
97 in cells, so that the propagator system remains "pure"
100 This probably mentioned a request for advice from the mailing list or
101 from the #clojure group.