     (and (not (some nil? comparisons))
          (every? #(<= % 0) comparisons)
          (some (partial = -1) comparisons))))
+
+(defn alt-set-vector [alt]
+  (mapv :elements (:args alt)))
+
+(def memoized-set-vectors-dominate? (memoize set-vectors-dominate?))
+
+(defn alt-dominates? [a b]
+  (memoized-set-vectors-dominate? (alt-set-vector a)
+                                  (alt-set-vector b)))
+
+(defn resolve-fn-call [system dispatch-state args]
+  (let [arity (count args)
+        alternatives (map (fn [[k alt]]
+                            (merge alt ((:match-fn alt)
+                                        system
+                                        (:feature-extractor dispatch-state)
+                                        args)))
+                          (get-in dispatch-state [:dispatch-map arity]))
+        matching-alternatives (filter :satisfied? alternatives)
+        frontier (pareto/elements (reduce pareto/insert
+                                          (pareto/frontier alt-dominates?)
+                                          matching-alternatives))]
+    (cond
+      (empty? frontier) (throw (ex-info "No matching set-fn for this arity."
+                                        (match-error-map
+                                         arity
+                                         alternatives)))
+      (< 1 (count frontier)) (throw
+                                                        (ex-info
+                                                         "Ambiguous set-based dispatch"
+                                                         (match-error-map
+                                                          arity
+                                                          matching-alternatives)))
+      :default (apply (-> frontier
+                          first
+                          :fn)
+                      args))))
+
+(defn dispatch-root [system dispatch-state]
+  (fn [& args]
+    (let [system (mark-called system)]
+      (if (empty? args)
+        dispatch-state
+        (resolve-fn-call system
+                         (deref dispatch-state)
+                         args)))))
+
+(defn initialize-dispatch-state [feature-extractor]
+  {:dispatch-map {}
+   :feature-extractor feature-extractor})
+
+(defn forward-set-fn [f]
+  (fn [& args]
+    (let [[system & rest-args] args]
+      (swap! system (fn [set-registry]
+                      (check-not-used set-registry)
+                      (apply f `(~set-registry ~@rest-args)))))))
+
+(defn add-method [state-atom arity method]
+  (swap! state-atom
+         (fn [state]
+           (update-in state [:dispatch-map arity]
+                      #(conj (or % {}) [(:args method) method])))))
+
+(def memoized-evaluate-query (memoize ss/evaluate-query))
+
+(defn evaluate-arg-match [system common-feature-extractor arg-spec arg]
+  (let [fe (or (:feature-extractor arg-spec)
+               common-feature-extractor)
+        element (fe arg)
+
+        _ (utils/data-assert (ss/element? system element)
+                             "Not an element"
+                             {:x element
+                              :elements (ss/all-elements system)})
+        
+        raw-query (:query arg-spec)
+        query (ss/normalize-query raw-query)
+
+        ;; TODO: This can be cached
+        elements (memoized-evaluate-query system query)
+
+        ;; NOTE: A a query can be satisfied even if the elements returned by
+        ;; evaluate-query is empty.
+        satisfied? (ss/satisfies-query? system query element)
+        
+        generality (count elements)]
+    (utils/map-of element satisfied? generality raw-query elements)))
 
 (defn make-match-fn [meta arg-specs]
   (fn [system common-feature-extractor args]

            [clojure.spec.alpha :as spec]
            [bluebell.utils.core :as utils]
            [bluebell.utils.specutils :as sutils]
            [clojure.set :as cljset])
  (:refer-clojure :exclude [complement any?]))



(defn match-error-map [arity alts]
  {:arity arity
   :alternatives (sort-by :generality (clean-alts alts))})

(defn compare-sets
  "Encode the relationship between two sets:
