I've recently been trying out Clojure Spec and ran into an unexpected error message. I've figured out that if you have a spec/or nested in a spec/and then the spec functions, after the spec/or branch, get passed a conformed value rather than the top level value.
You can see this in the printed value of "v" here (contrived example):
(spec/valid? (spec/and (spec/or :always-true (constantly true))
(fn [v]
(println "v:" v)
(constantly true)))
nil)
v: [:always-true nil]
=> true
I think this may be intentional from the doc string of spec/and:
Takes predicate/spec-forms, e.g.
(s/and even? #(< % 42))
Returns a spec that returns the conformed value. Successive conformed values propagate through rest of predicates.
But this seems counterintuitive to me as it would hamper reuse of spec predicates, because they'd need to be written to accept "[<or branch> <actual value>]".
Things get even worse if you have multiple spec/or branches:
(spec/valid? (spec/and (spec/or :always-true (constantly true))
(spec/or :also-always-true (constantly true))
(fn [v]
(println "v:" v)
(constantly true)))
nil)
v: [:also-always-true [:always-true nil]]
=> true
Have I missed something fundamental here?
s/nonconforming
instead of the conformer. – Benedic