refactor propagator to remove remaining references to cell

now expects inputs and outputs to be lambdas that call cell/content and
cell/add-content! respectively
This commit is contained in:
sorrel 2024-04-04 12:38:49 -04:00
parent 35e86859e8
commit 369fd89e62

View file

@ -1,45 +1,53 @@
(ns prop-net.propagator (ns prop-net.propagator)
(:require [prop-net.cell :as c]))
(def ^:private no-output [])
(defn- no-output? [output]
(= output no-output))
(defprotocol IPropagator (defprotocol IPropagator
(inputs [this]) (inputs
(output [this]) [this]
(add-input! [this input-cell]) "returns the functions to be called to retrieve the propagators inputs")
(add-output! [this output-cell]) (output
(apply! [this])) [this]
"returns the function to be called to set the result content of output cell")
(add-input!
[this input-lookup]
"add an input function to retrieve the content of a cell")
(add-output!
[this output-set!]
"add an output function to set the content of a cell")
(apply!
[this]
"applies the propagator function to results of all input-lookup
calls and calls the output function with the result"))
(defrecord Propagator (defrecord Propagator
[inputs output function] [input-getters output-setter function]
IPropagator IPropagator
(inputs [this] (deref (:inputs this))) (inputs [this] (deref (:input-getters this)))
(output [this] (deref (:output this))) (output [this] (deref (:output-setter this)))
(add-input! [this input-cell] (add-input! [this input-func]
;; this is some java shenanigans prop_net.cell.Cell (do (swap! (:input-getters this) conj input-func)
(when (not (instance? prop_net.cell.Cell input-cell)) :ok))
(throw (ex-info "Input must be a cell" {:input input-cell}))) (add-output! [this output-set!]
(let [old-inputs (deref (:inputs this))] (if (no-output? (output this))
(do (swap! (:inputs this) conj input-cell) (do (reset! (:output-setter this) output-set!)
:ok)))
(add-output! [this output-cell]
;; TODO for some reason instance? is not evaluating to true here, but types should really be checked
;; from the net itself
;; (when (not (instance? prop_net.cell.Cell output-cell))
;; (throw (ex-info "Output must be a cell" {:output output-cell
;; :type (type output-cell)})))
(if (c/nothing? (deref (:output this)))
(do (reset! (:output this) output-cell)
:ok) :ok)
(throw (ex-info "Output already set" {:propagator this :conflict output})))) (throw (ex-info "Output cell already present" {:propagator this :conflict output}))))
;; apply will call output with the result of calling :function with all inputs
(apply! [this] (apply! [this]
(let [input-cells (deref (:inputs this)) (let [input-getters (vec (inputs this))
output-cell (deref (:outputs this))] output-set! (output this)]
(c/add-content! output-cell (apply (:function this) (output-set! (apply (:function this)
(map c/content input-cells)))))) ;; there might be a cleaner way to apply each lookup?
(map (fn [lookup] (lookup))
input-getters))))))
(defn function->propagator (defn function->propagator
[func] [func]
(map->Propagator (map->Propagator
{:inputs (atom #{}) {:input-getters (atom #{})
:output (atom c/nothing) :output-setter (atom no-output)
:function func})) :function func}))