The clojure.spec.alpha API has a macro called conformer with this description:
Usage: (conformer f) (conformer f unf) takes a predicate function with the semantics of conform i.e. it should return either a (possibly converted) value or :clojure.spec.alpha/invalid, and returns a spec that uses it as a predicate/conformer. Optionally takes a second fn that does unform of result of first
This is unclear to me, if not esoteric.
What is it used for? What is the "unformer" (shouldn't that be an "unconformer") used for? I suppose to recreate the original data from the returned "conformed value"?.
Update
After 15 minutes of experiment, it seems to be to create a new "spec" from a "predicate" (the "spec" having something special going??)
I tried
(require '[clojure.spec.alpha :as s :refer [valid? explain conform conformer]])
; ---
; Using purely clojure.spec.alpha:
; ---
(s/def ::vtx-x float?)
(s/def ::vtx-y float?)
(s/def ::vertex (s/keys :req [::vtx-x ::vtx-y]))
(type (s/get-spec ::vertex))
;=> clojure.spec.alpha$map_spec_impl$reify__1997
(conform ::vertex { ::vtx-x 1.0 ::vtx-y 2.0 })
;=> #:user{:vtx-x 1.0, :vtx-y 2.0}
(valid? ::vertex { ::vtx-x 1.0 ::vtx-y 2.0 })
;=> true
(conform ::vertex { ::vtx-x 1.0 })
;=> :clojure.spec.alpha/invalid
; ---
; Using my own special sauce predicate function, where the conformed
; value carries additional information ... maybe for a debugging system?
; ---
(defn my-vertex-conformer [v]
(when-let [ { x ::vtx-x y ::vtx-y } v ]
(if (and (float? x) (float? y))
[:comment "Vertex conforms!" :something (+ x y) :orig v]
; else
:clojure.spec.alpha/invalid)))
(defn my-vertex-unformer [conf-v] (get conf-v :orig))
(s/def ::my-vertex (conformer my-vertex-conformer my-vertex-unformer))
(type (s/get-spec ::my-vertex))
;=> clojure.spec.alpha$spec_impl$reify__2059
(conform ::my-vertex { ::vtx-x 1.0 ::vtx-y 2.0 })
;=> [:comment "Vertex conforms!" :something 3.0
;=> :orig #:user{:vtx-x 1.0, :vtx-y 2.0}]
(valid? ::my-vertex { ::vtx-x 1.0 ::vtx-y 2.0 })
;=> true
(conform ::my-vertex { ::vtx-x 1.0 })
;=> :clojure.spec.alpha/invalid
Bonus, amazingly no exception here, is this an oversight?
(conformer map?)
;=> #object[clojure.spec.alpha$spec_impl$reify__2059 0x770b843 "clojure.spec.alpha$spec_impl$reify__2059@770b843"]
(type (conformer map?))
;=> clojure.spec.alpha$spec_impl$reify__2059