Skip to content

Instantly share code, notes, and snippets.

@eschulte
Created May 17, 2010 17:22
(ns
#^{:author "Eric Schulte",
:license "GPLV3",
:doc "Simple concurrent propagator system."}
propagator
(:use clojure.contrib.repl-utils clojure.contrib.math))
(defmacro cell "Define a new cell."
[name state]
`(def ~name (agent ~state)))
(defn set-cell "Set the value of a cell" [cell value]
(send cell (fn [_] value)))
(defmacro propagator "Define a new propagator."
[name in-cells out-cells & body]
`(do
(defn ~(with-meta name
(assoc (meta name)
:in-cells in-cells :out-cells out-cells))
~in-cells ~@body)
(doseq [cell# ~in-cells] (add-neighbor cell# ~name))
~name))
(defmacro run-propagator
"Run a propagator, first collect the most recent values from all
cells associated with the propagator, then evaluate."
[propagator]
`(let [results# (apply ~propagator (map deref (:in-cells ^#'~propagator)))]
(doseq [cell# (:out-cells ^#'~propagator)]
(when (not (= @cell# results#))
(send cell# (fn [_#] results#))))
results#))
(defmacro add-neighbor "Add a neighbor to the given cell."
[cell neighbor]
`(add-watcher
~cell :send
(agent nil :validator (fn [_#] (do (future (run-propagator ~neighbor)) true)))
(fn [_# _#])))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment