Fork me on GitHub

is there a way to in-line this: (s/def ::a integer?) (s/keys :req-un [::a]) so that I can state I expect ::a in the map that should be checked against integer? without having to specify ::a first?


@chillenious no, you could write a macro to do something like (my-keys :req-un [(::a integer?)]) that expands to it


@chillenious that's by design, see - Map specs should be of keysets only


Yeah, I was afraid you were going to say that 🙂 I can't be the first one who thinks that that's a PITA though. I very often have the situation where I'd like to use a different key from the 'type'.


That looks great, will try it out later this week.


@chillenious I encourage you to avoid this, there are many reasons for spec to encourage doing things in the way it does, to encourage you to have value definitions and just make compositions out of it, if you start thinking on your data as records you gonna lose a lot of the benefits on the long run, I recommend watching this presentation from Rich, where he talks a lot about the grand ideas and why things are the way they are:


I'll look at it, thanks. I'm using this as part of test code where I want some validation and documentation as to what data structures can/ should be used. So it's as important to me that it is easy to read and terse, and doesn't have to be a perfect water tight solution for all things spec 🙂


I noticed when a spec is created with (s/with-gen) it loses track of the original form:


(s/def ::some-spec (s/with-gen int? #(s/gen int?)))
=> :user/some-spec
(s/form ::some-spec)
=> :clojure.spec.alpha/unknown


but doing it using the (s/def (s/spec int? :gen #(s/gen int?))) works fine


(s/def ::other-spec (s/spec int? :gen #(s/gen int?)))
=> :user/other-spec
(s/form ::other-spec)
=> clojure.core/int?


is this expected?

Alex Miller (Clojure team)17:05:41

there’s a patch pending to fix this


There was a question last year about speccing a binary tree:

(def BinaryTree 
  (maybe ;; any empty binary tree is represented by nil
   {:value long 
    :left (recursive #‘BinaryTree) 
    :right (recursive #‘BinaryTree)}))


@alexmiller: you told Andrey Grin :“Yes, you can create recursive definitions by registering a spec that refers to itself via registered name (a namespaced keyword).“. I can’t find a way to do it, could please post a snippet of code ?



(s/def :bt/value number?)
(s/def :bt/left (s/nilable :a/bt))  ;;<- recursive
(s/def :bt/right (s/nilable :a/bt))  ;;<- recursive
(s/def :a/bt
      :req-un [:bt/value]
      :opt-un [:bt/left :bt/right])))

(s/explain :a/bt
  {:value 1
   :left {:value 21 :right {:value 31}}
   :right {:value 22 :left {:value 32 :right {:value 4} :left {:value 33}}}})

=> nil


s/exercise, however, stackoverflows at different points, so might need to tinker with that.


(binding [s/*recursion-limit* 2]
 (map first (s/exercise :a/bt 3)))
({:value -1.0, :right {:value -1}, :left nil}
 {:value -1,
  :left {:value -3.0, :left {:value -1, :right {:value 0.75}}},
  :right {:value 0}}
 {:value 0})


@alexmiller I was having this idea yesterday, about spec hierarchy tracking, currently when you define a spec from another (eg: (s/def ::something ::other-thing)) the resolving happens on definition time, I understand that is preferable for performance reasons, but doing that makes us lose track of the hierarchy. I was implementing a coerce engine on top of spec, and I miss having this hierarchy information, so I was thinking that we could have Clojure hierarchy for the specs, so when defining those we do a derive on those keywords, so we would have this information aside available for use, do you think this is a reasonable feature to have on spec?

Alex Miller (Clojure team)19:05:05

I don’t know about all that. there are some open tickets about the resolution aspects that I expect will be addressed.

Alex Miller (Clojure team)19:05:28

it is not the intent that you lose that tracking now


for example, given the following specs:


(s/def ::a int?)
(s/def ::b ::a)
(s/def ::c ::b)


is there a way, starting from ::c to know that it is derived from ::b and ::a?

Alex Miller (Clojure team)19:05:38

but things like and make me think that not everything is exactly right in this area


interesting, I didn't knew that get-spec would do that, and testing with the previous example works


glad to hear that my assumptions were wrong on this


how do I make a spec refer to a spec in another ns? I did (s/fdef ::name ::storage/name) but I just get No value supplied for key: ::storage/name


never mind, I’m an idiot and meant s/def


Thx @misha. Would it be possible to have a fn to create that kind of spec with the 'number?' predicate being passed as a parameter to this fn ?