          (fn [x#]
            (instance? ~?type x#)))
        (def ~(document-with-arglist ?constructor
-                                 (vec ?constructor-args)
-                                 (str "Construct a `" ?type "`"
-                                      (name-doc ?type)
-                                      " record.\n"
-                                      (apply str
-                                             (map (fn [[?field ?accessor ?lens]]
-                                                    (str "\n`" ?field "`" (name-doc ?field) ": access via " (reference ?accessor)
-                                                         (if ?lens
-                                                           (str ", lens " (reference ?lens))
-                                                           "")))
-                                                  ?field-triples))))
+                                    (vec ?constructor-args)
+                                    (str "Construct a `" ?type "`"
+                                         (name-doc ?type)
+                                         " record.\n"
+                                         (apply str
+                                                (map (fn [[?field ?accessor ?lens]]
+                                                       (str "\n`" ?field "`" (name-doc ?field) ": access via " (reference ?accessor)
+                                                            (if ?lens
+                                                              (str ", lens " (reference ?lens))
+                                                              "")))
+                                                     ?field-triples))))
          (fn [~@?constructor-args]
            (new ~?type
                 ~@(map (fn [[?field _]]

               (resolve* accessor)))
           ?constructor-args)))))

#?(:clj
(defmacro define-record-type
  "Attach doc properties to the type and the field names to get reasonable docstrings."
  [?type ?constructor-call ?predicate ?field-specs & ?opt+specs]
  (when-not (and (list? ?constructor-call)
                 (not (empty? ?constructor-call)))
    (throw (throw-illegal-argument-exception (str "constructor call must be a list in " *ns* " " (meta &form)))))
  (when-not (vector? ?field-specs)
    (throw (throw-illegal-argument-exception (str "field specs must be a vector in " *ns* " " (meta &form)))))
  (when-not (even? (count (remove seq? ?field-specs)))
    (throw (throw-illegal-argument-exception (str "odd number of elements in field specs in " *ns* " " (meta &form)))))
  (when-not (every? true? (map #(= 3 (count %1)) (filter seq? ?field-specs)))
    (throw (throw-illegal-argument-exception (str "wrong number of elements in field specs with lens in " *ns* " " (meta &form)))))

  (let [?field-triples (loop [specs (seq ?field-specs)
                              triples '()]
                         (if (empty? specs)
                           (reverse triples)
                           (let [spec (first specs)]

                             (cond
                              (list? spec)
                              (do
                                (when-not (and (= 3 (count spec))
                                               (every? symbol spec))
                                  (throw-illegal-argument-exception (str "invalid field spec " spec " in " *ns* " " (meta &form))))
                                (recur (rest specs) (list* spec triples)))

                              (symbol? spec)
                              (do
                                (when (empty? (rest specs))
                                  (throw (throw-illegal-argument-exception (str "incomplete field spec for " spec " in " *ns* " " (meta &form)))))
                                (when-not (symbol? (fnext specs))
                                  (throw (throw-illegal-argument-exception (str "invalid accessor " (fnext specs) " for " spec " in " *ns* " " (meta &form)))))
                                (recur (nnext specs)
                                       (list* [spec (fnext specs) nil] triples)))

                              :else
                              (throw (throw-illegal-argument-exception (str "invalid field spec " spec " in " *ns* " " (meta &form))))))))

        ?constructor (first ?constructor-call)
        ?constructor-args (rest ?constructor-call)
        ?constructor-args-set (set ?constructor-args)
        document (fn [n doc]
                   (vary-meta n
                              (fn [m]
                                (if (contains? m :doc)
                                  m
                                  (assoc m :doc doc)))))
        document-with-arglist (fn [n arglist doc]
                                (vary-meta n
                                           (fn [m]
                                             (let [m (if (contains? m :doc)
                                                       m
                                                       (assoc m :doc doc))]
                                               (if (contains? m :arglists)
                                                 m
                                                 (assoc m :arglists `'(~arglist)))))))
        name-doc (fn [field]
                    (if-let [doc (:doc (meta field))]
                      (str " (" doc ")")
                      ""))

        ?field-names (map first ?field-triples)
        reference (fn [name]
                    (str "[[" (ns-name *ns*) "/" name "]]"))
        ?docref (str "See " (reference ?constructor) ".")

        record-meta `(make-record-meta ~?predicate ~?constructor ~?constructor-args ~?field-triples)]

    (let [?field-names-set (set ?field-names)]
      (doseq [?constructor-arg ?constructor-args]
        (when-not (contains? ?field-names-set ?constructor-arg)
          (throw (throw-illegal-argument-exception (str "constructor argument " ?constructor-arg " is not a field in " *ns* " " (meta &form)))))))

    `(do
       ~(let [fields (mapv first ?field-triples)]
          (validate-fields fields ?type)

                                                                    `(~?shove-accessor ~?data)))
                                                                ?field-triples)))))))
                           '()))))
                 ?field-triples))))

#?(:clj
(defmacro define-record-type
  "Attach doc properties to the type and the field names to get reasonable docstrings."
  [?type ?constructor-call ?predicate ?field-specs & ?opt+specs]
  (when-not (and (list? ?constructor-call)
                 (not (empty? ?constructor-call)))
    (throw (throw-illegal-argument-exception (str "constructor call must be a list in " *ns* " " (meta &form)))))
  (when-not (vector? ?field-specs)
    (throw (throw-illegal-argument-exception (str "field specs must be a vector in " *ns* " " (meta &form)))))
  (when-not (even? (count (remove seq? ?field-specs)))
    (throw (throw-illegal-argument-exception (str "odd number of elements in field specs in " *ns* " " (meta &form)))))
  (when-not (every? true? (map #(= 3 (count %1)) (filter seq? ?field-specs)))
    (throw (throw-illegal-argument-exception (str "wrong number of elements in field specs with lens in " *ns* " " (meta &form)))))

  (let [?field-triples (loop [specs (seq ?field-specs)
                              triples '()]
                         (if (empty? specs)
                           (reverse triples)
                           (let [spec (first specs)]

                             (cond
                              (list? spec)
                              (do
                                (when-not (and (= 3 (count spec))
                                               (every? symbol spec))
                                  (throw-illegal-argument-exception (str "invalid field spec " spec " in " *ns* " " (meta &form))))
                                (recur (rest specs) (list* spec triples)))

                              (symbol? spec)
                              (do
                                (when (empty? (rest specs))
                                  (throw (throw-illegal-argument-exception (str "incomplete field spec for " spec " in " *ns* " " (meta &form)))))
                                (when-not (symbol? (fnext specs))
                                  (throw (throw-illegal-argument-exception (str "invalid accessor " (fnext specs) " for " spec " in " *ns* " " (meta &form)))))
                                (recur (nnext specs)
                                       (list* [spec (fnext specs) nil] triples)))

                              :else
                              (throw (throw-illegal-argument-exception (str "invalid field spec " spec " in " *ns* " " (meta &form))))))))

        ?constructor (first ?constructor-call)
        ?constructor-args (rest ?constructor-call)
        ?field-names (map first ?field-triples)]
    (emit-java-record-definition ?type ?constructor ?constructor-args ?predicate ?field-triples ?opt+specs)))
)

(defn predicate->record-meta [predicate]
  ;; Expects a namespace resolved predicate
