Fork me on GitHub
#clojure-spec
<
2017-11-13
>
qqq04:11:48

is there a way in spec to say ::x is a vector of numbers ::y is a vector of numbers ::s is a string and the three have the same length (thisxis regarding to an s/keys)

qqq04:11:42

this is what I have so far:

(s/def ::text-x (s/coll-of number? :kind vector?))
(s/def ::text-y (s/coll-of number? :kind vector?))
(s/def ::text-str string?)
but it's not clear to me how to specify the three have the same length

seancorfield06:11:35

@qqq Are you using them in a context together? Sounds like you could s/and a length check on top of whatever structure uses all three?

qqq06:11:53

@seancorfield

(s/def ::text-x (s/coll-of number? :kind vector?))
(s/def ::text-y (s/coll-of number? :kind vector?))
(s/def ::text-str string?)
(s/def ::svg-text (s/keys :req [::text-x ::text-y ::text-str ]))

is what I have so far

qqq06:11:16

You are recommending (s/and (s/keys ...1) ...2) ?

qqq06:11:32

in ...2 , how do I access the text-x, text-y, text-str fields ?

jumar07:11:36

@qqq something like this?

(defn- vals-same-length?
  [m]
  (->> (vals m)
       (map count)
       (apply =)))
(s/def ::svg-text-same-length (s/and (s/keys :req [::text-x ::text-y ::text-str ])
                                     vals-same-length?))

(s/valid? ::svg-text-same-length {::text-x   [1 2 3]
                                  ::text-y   [10 20 30]
                                  ::text-str "abc"})
(There might be more straightforward implementation of vals-same-length?)

qqq07:11:33

@jumar: I did not realize I can just pass in an arbitrary clojure function.

qqq07:11:47

This is very useful, thanks!

seancorfield08:11:00

(sorry, was distracted by the amazing availability of early 80's German electronica on iTunes these days... yes, @qqq what @jumar said... when you use s/and you can have any predicate and it has access to the entire form being processed, so you could access just ::text-x, ::text-y, ::text-str if you wanted, or vals to get all the map's values.

seancorfield08:11:39

I was thinking you were using this with s/cat for argument specifications, but the same principle applies. Specs are just predicates. It's all functions, all the way down 🙂

deg19:11:16

I need to define a spec for a map that holds keys owned by multiple parts of my code. So, looking a a tasteful way to build it incrementally from multiple files. (So that each namespace adds in the parts it understands). This strikes me as non-trivial, especially since I can't just have a defonce'd atom that I assoc into. Because s/keys is a macro, I need to assemble only after I've gathered all the parts. Sounds like I need to think about file loading order and other issues that I've ignored until now in my Clojure/Script. Is there a straightforward way to do this? Or am I barking up the wrong trees?

hiredman19:11:53

I am not sure what you are asking?

hiredman19:11:09

if each key is owned by a different part of your code, and you want to spec each key do that

hiredman19:11:27

and then in whatever central place, create your keys spec from each key

hiredman19:11:46

the structure of clojure requires you to have a central place, the way the ns macro and everything else works requires you to have a defined load order and explicitly require the code you need access to

qqq19:11:07

does s/coll-of check every element, or does it randomly pick a few and test them ?

taylor19:11:39

> coll-of will exhaustively conform every value

taylor19:11:23

as opposed to every: > Note that ‘every’ does not do exhaustive checking, rather it samples coll-check-limit elements.

bbloom20:11:46

been away for a bit - i remember core had some private convenience macro for checking macro invocations. what’s the latest recommendation on that? i actually want to use the spec for parsing inside the macro, but it’s a bit awkward to conform and then if that fails explain, etc

deg20:11:30

@hiredman - I was looking for a way to avoid having to know about all the parts at one central place.

deg20:11:52

That is, I don't want to say (s/keys :opt [ns1/key1 ns2/key2 ,,,]), but instead create the spec dynamically. This seems trickier than it should be, since keys is a macro, so I can't just do a trivial atom/assoc/apply dance.

hiredman20:11:29

it sounds like you want the already existing feature in spec where a s/keys spec will check specs for keys that exist in the map that have a spec even if they aren't part of the s/keys spec

qqq21:11:39

I assume this is more appropriate for blog post reading rather than discussion: is there a good writeup somewhere of qualified vs unqialified names for specs ? Everything I've done so far in clojure is unqualified, i.e. :foo kws, but looking at spec, it seems like the default / preferred wa yis to be qualified i.e. ::foo or :blah.namespace/foo

arohner21:11:31

I have a uuid. Is there a smart way to bias the generator so I can control the distribution of uuids? i.e. completely random vs. power law?

arohner21:11:07

I’m aware of e.g. gen/elements, was wondering if there’s something else

gfredericks21:11:33

you're trying to get collisions?

arohner21:11:58

yes, some of the time

arohner21:11:29

but I’d really like e.g. power laws on repeat UUIDs, so out of 1000 uuids, one appears 100 times, one appears 20 times, etc.

arohner21:11:47

reading the spec source was informative. I’ll just with-gen with a UUID constructor

gfredericks21:11:39

where will you get the args for the constructor?

arohner21:11:57

type 5s are deterministic, and I suspect I can create v1s by specifying a unix time

gfredericks21:11:58

if you use gen/large-integer and gen/fmap that to the type-3 uuid constructor, that will give you something like the distribution you want

gfredericks21:11:20

keep in mind how distribution relates to size

arohner21:11:37

can you expand on that?

gfredericks21:11:04

I also talked about it some here if you liked faces and voices and slides and things https://youtu.be/F4VZPxLZUdA?t=25m26s

arohner21:11:47

very useful, thank you