 ;; los and his are inclusive
 
 ;; propagate updates the current lo/hi for each var and may set the solver to failed
-;;   returns the val of the current key (only has to be correct when all its vars are fixed)
 ;; split-left either:
 ;;   breaks the solutions into two branches, sets the left branch, returns true
 ;;   has only one possible solution, does nothing, returns false
 ;; split-right:
 ;;   breaks the solutions into two branches, sets the right branch
-;; val returns the number of solutions with this key (assumes all vars are fixed)
 
 (deftype Contains [iterator vars scratch-key]
   Object
   (reset [this solver constraint]
          (.reset iterator))
-  (val [this solver constraints]
-       ;; TODO somewhat uncomfortable with the fact that this is stateful
-       ;; could store current key and check key= instead
-       (.val iterator))
   (propagate [this solver constraint]
              (let [los (.-los solver)
                    his (.-his solver)]

                (do
                  (.split this)
                  (recur 0)))))))
  (val [this]
       (let [result 1]
         (dotimes [constraint (alength constraints)]
           (set!! result (* result (.val (aget constraints constraint) this constraint))))
         result))
  (elems [this]
         (let [results #js []]
           (loop []
             (let [result (.next this)]
               (when-not (nil? result)
                 (apush results result)
                 (apush results (.val this))
                 (recur))))
         results))
  ISeqable
  (-seq [this]
        (seq (map vec (partition 2 (.elems this))))))

(defn solver [num-vars constraints]
  (let [los (least-key num-vars)

  (reset [this key]
         (set! node (.-root tree))
         (set! ix 0))
  (seek-gt [this key]
           (loop []
             (if (and (instance? Node (.-parent node))
