 
 ;; The interface
 
-(defmacro- container-checker [name checker-fn]
-  `(with-meta
-     (fn [expected# & kind#]
-       (vary-meta
-         (named '~name expected#
-                (fn [actual#]
-                  ;; (prn "checking" actual# expected# kind#)
-                  (add-actual actual#
-			      (if (chatty-checker-falsehood?
-				   (compatibility-failure actual# expected# kind#))
-				(compatibility-failure actual# expected# kind#)
-				(try (~checker-fn actual# expected# kind#)
-				     (catch Error ex#
-				       (tag-as-chatty-falsehood {
-								 :notes [(.getMessage ex#)]}))))))
-		merge
-		{:midje/chatty-checker true, :midje/checker true}))
-       {:midje/checker true})))
-
-(def contains (container-checker contains
+(defn- container-checker-maker [name checker-fn]
+  (tag-as-checker
+   (fn [expected & kind]
+      (tag-as-chatty-checker
+       (named name expected
+              (fn [actual]
+                (add-actual actual
+                            (try (checker-fn actual expected kind)
+                                 (catch Error ex
+                                   (noted-falsehood (.getMessage ex)))))))))))
+
+(def contains (container-checker-maker 'contains
     (fn [actual expected kind]
       (let [ [actual expected kind] (standardized-arguments actual expected kind)]
         (cond (regex? expected)

  [ [binding-var] [function & arglist] ]
  (let [result-symbol (gensym "chatty-intermediate-results-")
        [complex-forms substituted-arglist] (chatty-untease result-symbol arglist)]
    `(with-meta (fn [~binding-var]
                  (let [~result-symbol (vector ~@complex-forms)]
                    (if (~function ~@substituted-arglist)
                      true
                      (let [pairs# (map vector '~complex-forms ~result-symbol)]
                        (tag-as-chatty-falsehood {:actual ~binding-var,
                                                  :intermediate-results pairs#})))))
       {:midje/chatty-checker true, :midje/checker true})))

;;Concerning Throwables

                   starting-candidate)))))

;; Initial argument processing

(defn compatibility-check [actual expected kind]
  "Fling an error of the combination of actual, expected, and kind won't work."
  ;; Throwing Errors is just an implementation convenience.
  (cond (regex? expected)
	(cond (and (not (sequential? actual))
		   (not (empty? kind)))
	      (throw (Error. (str "I don't know how to make sense of a "
				  "regular expression applied "
				  kind "."))))

	(not (collection-like? actual))
	(throw (Error. (str "You can't compare " (pr-str actual) " (" (type actual) 
			    ") to " (pr-str expected) " (" (type expected) ").")))
	
	(and (map? actual)
	     (not (map? expected)))
	(try (into {} expected)
	     (catch Throwable ex
	       (throw (Error. (str "If " (pr-str actual) " is a map, "
				   (pr-str expected)
				   " should look like map entries.")))))))

  
(defn- standardized-arguments [actual expected kind]
  "Reduce arguments to standard forms so there are fewer combinations to
   consider. Also blow up for some incompatible forms."

  (compatibility-check actual expected kind)
  (cond (sequential? actual)
	(cond (set? expected)
	      [actual (vec expected) (union kind #{:in-any-order})]
