Fork me on GitHub
#clojure-spec
<
2017-05-17
>
chillenious14:05:04

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?

luxbock14:05:55

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

moxaj14:05:51

@chillenious that's by design, see https://clojure.org/about/spec - Map specs should be of keysets only

chillenious14:05:02

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'.

chillenious15:05:38

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

wilkerlucio15:05:07

@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: https://vimeo.com/195711510

chillenious15:05:59

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 🙂

wilkerlucio15:05:44

hello 🙂

wilkerlucio15:05:05

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

wilkerlucio15:05:51

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

wilkerlucio15:05:42

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

wilkerlucio15:05:02

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

wilkerlucio15:05:15

is this expected?

Alex Miller (Clojure team)17:05:41

there’s a patch pending to fix this

gphilipp19:05:40

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)}))

gphilipp19:05:32

@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 ?

misha19:05:52

@gphilipp

(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
  (s/nilable
    (s/keys
      :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}}}})

Success!
=> nil

misha19:05:59

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

misha19:05:29

(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})

wilkerlucio19:05:35

@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

wilkerlucio19:05:02

for example, given the following specs:

wilkerlucio19:05:17

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

wilkerlucio19:05:40

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 https://dev.clojure.org/jira/browse/CLJ-2067 and https://dev.clojure.org/jira/browse/CLJ-2079 make me think that not everything is exactly right in this area

wilkerlucio19:05:40

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

wilkerlucio19:05:23

glad to hear that my assumptions were wrong on this

lvh22:05:39

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

lvh22:05:18

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

gphilipp22:05:18

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 ?