field-validation-error-map

Clojure
(require '[clojure.string :as str])

(defn validate
  "Returns {:ok bool :errors {field [messages]} :value data}. Rules map a field
   to [predicate message] pairs; every failing predicate adds its message."
  [rules data]
  (let [errors (reduce-kv
                (fn [m field checks]
                  (let [msgs (for [[pred msg] checks :when (not (pred (get data field)))] msg)]
                    (if (seq msgs) (assoc m field (vec msgs)) m)))
                {} rules)]
    {:ok (empty? errors) :errors errors :value data}))

;; (validate {:email [[(complement str/blank?) "required"]]} {:email ""})