   (get x :b)
 
 
+  (= eg (fact-shape ::eg "[a] has a [b] with a [c]"))
+
   (fact (fact-shape ::eg "[a] has a [b] with a [c]") #js ["a" "b" "c"])
 
   (= x x)

  IEquiv
  (-equiv [this other]
          (and (instance? Fact other)
               (= (.-id shape) (.-id (.-shape other)))
               (loop [i 0]
                 (if (>= i (alength values))
                   true
                   (when (= (aget values i) (aget (.-values other) i))
                     (recur (+ i 1)))))))

  IHash
  (-hash [this] (caching-hash this hash-array __hash))

(deftype FactShape [id madlib keys]
  Object
  (toString [this]
            (apply str (interleave madlib (map (fn [k] (str "[" (name k) "]")) keys))))
  IEquiv
  (-equiv [this other]
          (and (instance? FactShape other)
               (= id (.-id other)))))

;; if given a shape behaves like a record, otherwise behaves like a vector
(deftype Fact [shape values ^:mutable __hash]
  Object
  (toString [this]
