Fork me on GitHub
#clojure-spec
<
2018-11-06
>
roklenarcic11:11:11

is there a way to spec map's key+value, but the key isn't specific

roklenarcic11:11:54

like how do I say: map key is symbol or keyword, if key is symbol then value must be string but if key is keyword then value must be integer

roklenarcic11:11:48

I tried s/coll-of :kind map? but that only conforms value

borkdude12:11:23

@roklenarcic can the map also have combinations of these key/val pairs?

borkdude12:11:34

in that case I would make a spec for the map-entry

alexmiller12:11:51

You can use s/every with an s/or of s/tuple for entry combinations

roklenarcic12:11:13

thank you alex, I'll try that

roklenarcic12:11:57

hm well every doesn't conform

roklenarcic12:11:54

hm... when using coll-of, if I specify kind as map? and if I don't specify kind, conforming works differently 😄

borkdude12:11:39

@roklenarcic specify it as a seq of tuples?

borkdude12:11:31

so something like (coll-of ::my-tuple-spec)

roklenarcic12:11:42

tuple spec is no better than map-of spec... each item is independent

borkdude12:11:10

::my-tuple-spec can spec independent things?

roklenarcic12:11:31

(s/tuple pred1 pred2)

roklenarcic12:11:45

you can't link type of 1 and type of 2

borkdude12:11:06

(s/or (s/tuple symbol? string?) (s/tuple s/keyword? int?))

roklenarcic12:11:25

so s/coll-of that?

borkdude12:11:03

and I guess :kind could optionally also be set to map?, it’s just an extra check

roklenarcic12:11:12

(s/conform (s/coll-of (s/or :s1 (s/tuple symbol? string?) :s2 (s/tuple keyword? int?))) '{a "A" :b 3})
=> {:s1 [a "A"], :s2 [:b 3]}

borkdude12:11:20

but often a seq of map-entries can be used in places where maps are used

roklenarcic12:11:29

this is completely different to how I would expect things to go

roklenarcic12:11:43

I would expect a collection of tuples

borkdude12:11:54

@roklenarcic you mean the conformed value?

roklenarcic12:11:09

this looks completely wrong and unexpected to me

borkdude12:11:00

it isn’t wrong, it’s conformed. else you get ::s/invalid

roklenarcic12:11:05

(s/conform (s/coll-of (s/or :s1 (s/tuple symbol? string?) :s2 (s/tuple keyword? int?))) '{a "A" :b 3 c "B"})
=> {:s1 [c "B"], :s2 [:b 3]}

roklenarcic12:11:15

see... now I lost a term

roklenarcic12:11:40

input map has 3 key-values

roklenarcic12:11:46

result has two items

borkdude12:11:25

so maybe every will help there?

roklenarcic12:11:02

nah, I'll just switch back

roklenarcic12:11:05

to :kind map?

roklenarcic12:11:10

and take vals

roklenarcic12:11:21

problem solved

borkdude12:11:25

if I had time I would help you figure it out, but I have to go now

roklenarcic12:11:49

don't worry, I have a solution, I was just looking for something more elegant

borkdude12:11:35

yes, (s/conform (s/every (s/or :s1 (s/tuple symbol? string?) :s2 (s/tuple keyword? int?))) '{a "A" :b 3 c "B"}) works

roklenarcic12:11:00

every doesn't do any conforming at all FYI

roklenarcic12:11:05

at least I think so

borkdude12:11:07

oh you want conforming

roklenarcic12:11:35

(s/coll-of x :kind map?), conforms key+value into value

roklenarcic12:11:04

so you just have to take (vals ) of value in the map then

borkdude12:11:46

@roklenarcic

(s/conform (s/cat :map-entries (s/* (s/alt :s1 (s/tuple symbol? string?) :s2 (s/tuple keyword? int?)))) '{a "A" :b 3 c "B"})

alexmiller14:11:12

I don’t think this approach will work on latest spec - regex specs now only work on sequential collections (too confusingly dangerous to do sequential spec’ing on unordered collections)

alexmiller14:11:20

(s/conform (s/coll-of (s/or :s1 (s/tuple symbol? string?) :s2 (s/tuple keyword? int?))) '{a "A" :b 3 c "B"})

alexmiller14:11:24

would be better

borkdude14:11:27

that was already proposed by me, but that didn’t work, because the result would be: {:s1 [c "B"], :s2 [:b 3]} and you lose map-entries

borkdude14:11:48

I guess you can call seq on the map first if it doesn’t work with the newest spec

borkdude14:11:33

every also works, but that doesn’t conform and the OP wanted that

alexmiller14:11:35

(s/conform (s/coll-of (s/or :s1 (s/tuple symbol? string?) :s2 (s/tuple keyword? int?)) :into []) '{a "A" :b 3 c "B"})

alexmiller14:11:03

=> [[:s1 [a "A"]] [:s2 [:b 3]] [:s1 [c "B"]]]

alexmiller14:11:55

user=> (s/conform (s/coll-of (s/nonconforming (s/or :s1 (s/tuple symbol? string?) :s2 (s/tuple keyword? int?))) :into []) '{a "A" :b 3 c "B"})
[[a "A"] [:b 3] [c "B"]]

alexmiller14:11:04

if you want to hide the or tag

borkdude14:11:51

aah, :into [], ok

roklenarcic12:11:38

well that's clever 🙂

martinklepsch13:11:01

I'm having some problems adding :args specs to a function, I think it kind of boils down to this:

(spec/def ::title string?)
(spec/def ::entry-x (spec/cat :title ::title))
(spec/valid? ::entry-x ["Title"])                     ; => true
(spec/valid? (spec/cat :entry ::entry-x) ["Title"])   ; => true
(spec/valid? (spec/cat :entry ::entry-x) [["Title"]]) ; => false
I would expect the additional cat to require additional wrapping but it appears that ::entrty-x and (spec/cat :entry ::entry-x) are identical for some reason.

borkdude13:11:27

I guess you can nest s/cat?

borkdude13:11:10

(s/def ::foo (s/cat :a int? :bcat (s/cat :b int?)))
(s/conform ::foo [1 2]) ;; {:a 1, :bcat {:b 2}}

alexmiller13:11:01

regex ops nest to describe the same structured collection

alexmiller13:11:07

if you need a new “level”, insert s/spec

martinklepsch13:11:25

Interesting I would have expected that spec to match [1 [2]] I guess

alexmiller13:11:40

this is covered in the spec guide

borkdude13:11:10

it behaves the same as s/alt, s/*, etc. they consume the same seq “level”

martinklepsch13:11:15

Ok, s/spec did the trick. Also found the section in the spec guide now

borkdude14:11:31

@roklenarcic please watch the thread, Alex gave some advice there

borkdude14:11:08

btw, handy link if you quickly want to check examples posted here: http://app.klipse.tech/?cljs_in=(require%20%27[clojure.spec.alpha%20:as%20s])

borkdude14:11:52

is this feature in clojure 1.10 related to upcoming changes in clojure.spec maybe? https://twitter.com/timbaldridge/status/1059815352106795008

alexmiller18:11:00

no, it’s a genericization of stuff from datafy

alexmiller18:11:16

although datafy is potentially something we will do in spec, still tbd

kirill.salykin14:11:06

what is instance based protocol polymorphism?

mpenet14:11:36

type vs instance

mpenet14:11:44

number vs 42

mpenet14:11:09

in short you could have a custom impl of some protocol fn bound to a value (via metadata) instead of a type

ghadi14:11:35

in clojurescript this is like specify!

mpenet14:11:37

well the number mention is not a good example 🙂 no meta

kirill.salykin14:11:00

cant you dispatch now based on meta?

kirill.salykin14:11:55

sorry for being annoying, but I am very curriuos about it 🙂

mpenet14:11:58

(defprotocol Foo (foo [x])) (foo (with-meta [42] {`foo (fn [x] :boo)})) -> :boo

kirill.salykin14:11:27

i will have a look, thanks!

mpenet14:11:28

super cool feature (not really related to spec tho, as far as we know)

borkdude14:11:56

well, I thought, maybe this way predicates could be bound to keywords and spec could use that

mpenet14:11:28

keywords do not support meta I believe

bronsa14:11:04

they don't, this is ~ specify limited to IObjs (modulo the different method resolution rules around direct impl)

jumar15:11:13

satisfies? doesn't work with the new "instance-based polymorphism"?

mpenet15:11:52

apparently not

bronsa15:11:31

no, I was looking at a related fix for CLJ-1814 but I think somebody should make a ticket just for this specific issue

ghadi15:11:12

^^ yes, please.

jumar15:11:11

Ok, I can do it.

jumar16:11:23

Here's the thing: https://dev.clojure.org/jira/browse/CLJ-2426 It's my first ticket so I hope it's clear.

ghadi16:11:40

it is, thanks @U06BE1L6T

🙂 4
eoliphant17:11:17

Hi, I'm trying to get a feel for where to 'draw the line' on more dynamic behavior in specs. I've created an EDN based data description language for one of my projects. I have it spec'ed out pretty thoroughly, but I have a situation where I have say :data/type that could be one of a fixed set of types (:string :long, etc) or a type that's defined elsewhere in the larger data structure I'm validating. my code is already doing some additional validation based on core.logic etc once the definitions are loaded. So just wondering if it's better to defer this type of check to that point

mathpunk18:11:20

Is there an equivalent of ns-unmap for a symbol you used spec/def on? (I suspect this question will reveal an error in my mental model of how symbols and specs relate)

didibus18:11:34

Just s/def it to nil

mathpunk18:11:51

🆒 thanks!

didibus18:11:59

If I remember correctly