                      (aget values i)
                      (recur (+ i 1)))))))))
 
-(defn id->fact-shape [id]
-  (js/eval (str (namespace id) "." (name id)))) ;; TODO assumes facts are created by deffact
-
 (defn fact-shape [id madlib&keys]
   (let [split-madlib&keys (clojure.string/split madlib&keys #"\[|\]")
         [madlib keys] [(take-nth 2 split-madlib&keys) (map keyword (take-nth 2 (rest split-madlib&keys)))]]

        (do
          (apush constant-values value)
          (apush constant-ixes ix))))
    (fn [fact]
      (when (= shape (.-shape fact))
        (let [source (.-values fact)]
          (loop [i 0]
            (if (< i (alength constant-values))
              (when (= (aget constant-values i) (aget source (aget constant-ixes i)))
                (recur (+ i 1)))
              (loop [i 0]
                (if (< i (alength dup-value-ixes))
                  (when (= (aget source (aget dup-value-ixes i)) (aget source (aget dup-var-ixes i)))
                    (recur (+ i 1)))
                  (let [sink (make-array (alength var-ixes))]
                    (dotimes [i (alength var-ixes)]
                      (aset sink i (aget source (aget var-ixes i))))
                    (Fact. nil sink nil)))))))))))

(comment
  (deffact eg "[a] has a [b] with a [c]")


  )

;; FLOWS

(defrecord Union [nodes])
(defrecord FilterMap [nodes fun&args])
(defrecord Index [nodes key-ixes])
(defrecord Lookup [nodes index-node key-ixes val-ixes])

(defn flow->nodes [flow]
  (:nodes flow))

;; FLOW PLAN

(defrecord FlowPlan [node->flow flow->node])

(defn flow-plan->flow-state [{:keys [node->flow]}]
  (let [node->state (into-array (for [_ node->flow] nil))
        node->out-nodes (into-array (for [_ node->flow] #js []))
        node->facts (into-array (for [_ node->flow] #js []))
        node->update! (into-array (for [_ node->flow] nil))]
    (dotimes [node (count node->flow)]
      (let [flow (nth node->flow node)]
        (aset node->state node
              (condp = (type flow)
                Union (transient #{})
                FilterMap nil
                Index (transient {})
                Lookup nil))
        (doseq [in-node (:nodes flow)]
          (apush (aget node->out-nodes in-node) node))
        (aset node->update! node
              (condp = (type flow)
                Union (union-update!)
                FilterMap (filter-map-update! (apply (resolve (first (:fun&args flow))) (rest (:fun&args flow))))
                Index (index-update! (:key-ixes flow))
                Lookup (lookup-update! (:index-node flow) (:key-ixes flow) (:val-ixes flow))))))
    (FlowState. node->state node->out-nodes node->facts node->update!)))

(defn memory->node [memory]
  (case memory
    :known 0
    :pretended 1
    :remembered 2
    :forgotten 3))

(defn memory->nodes [memory]
  (case memory
    :known [0]
    :pretended [1]
    :remembered [2]
    :forgotten [3]
    :known&pretended [0 1]))

(def empty-flow-plan
  (FlowPlan. [(Union. #{}) (Union. #{}) (Union. #{}) (Union. #{})] {}))

(defn add-output [flow-plan node memory]
  (update-in flow-plan [:node->flow (memory->node memory) :nodes] conj node))

(defn add-flow [{:keys [node->flow flow->node] :as flow-plan} flow]
  (if-let [node (flow->node flow)]
    [flow-plan node]
    (let [node (count node->flow)
          node->flow (conj node->flow flow)
          flow->node (assoc flow->node flow node)]
      [(FlowPlan. node->flow flow->node) node])))

;; IXES

(defn ix-of [vector value]
