Fork me on GitHub
#clojure-spec
<
2016-06-18
>
wilkerlucio00:06:39

I noticed (s/exercice number?) can generate some NaN entries on cljs, is that by design?

leongrapenthin00:06:33

So conform-spec as described above can apparently be implemented quite easily via (defn conform-spec [s] (s/and (s/conformer #(s/unform s %)) s))

leongrapenthin00:06:21

But it would probably be more valuable if a spec could give a spec of what its conform* returns

wildermuthn03:06:32

Is there a changelog for Spec? I’m looking at some of the recent commits to cljs.spec, and see that the docs have been updated. But would be great to know if there was another place to reference to see the updates.

wildermuthn04:06:42

The more I learn about Spec, the more I think it is going to be regarded one of the essential Clojure features, on par with immutable data. For instance, I found out about conformer, and not ten minutes later had the beginning of a solution that I’ve never had for parsing JSON enums in a sane way. I shared this on #C03S1L9DN, but interested in getting feedback if I’m going at this the wrong way:

vikeri08:06:45

A question about spec and generators, is it able to generate data from a spec directly or does it generate data and test it against the spec? As an example I suppose that a generator for string will only generate strings, but what if you have some slightly more complicated predicates like strings with the length 3? Will it understand to only generate strings with the length three? I guess this would need some way of inverting an if statement, which sounds difficult. The main question in hence: How ”smart” can the generator be?

Alex Miller (Clojure team)10:06:31

If you have (s/and string? #(= (count %) 3)) the and generator generates based on the first pred, then filters based on the subsequent ones

Alex Miller (Clojure team)10:06:04

So it will generate random strings and keep those that are length 3

Alex Miller (Clojure team)10:06:43

That's probably a restrictive enough filter that you'll need to supply a custom generator

Alex Miller (Clojure team)10:06:40

@wildermuthn: I list incremental changes for each release in the announcement notes in the Clojure mailing list

Alex Miller (Clojure team)10:06:28

@wildermuthn: not clear to me what you're asking about with conformers above

ghadi12:06:41

@alexmiller: s/every has a tiny typo in it causing this:

user=> (s/valid? (s/every #{:foo}) [:foo :foo])
true
user=> (s/valid? (s/every #{:foo}) 42)
true  ;; incorrect

ghadi12:06:29

s/:invalid/::invalid

nha14:06:19

What is wrong with the following ?

(defn add []
  "a")

(s/fdef add
        :ret int?)

(s/instrument #'add)

(add) ;;=> "a"

nha14:06:11

I was expecting an error on the return value.

minimal14:06:14

Instrument was changed to only check :args

nha14:06:09

Ooh so how do I check the return value ? (ie. what would be a simple test here ?)

nha14:06:29

Also is there a constraint on the order of things ? Can I s/fdef before defn-ing a function ? Can I s/instrument-all when I want ?

minimal14:06:04

For now you have to use the functions from the clojure.spec.test namespace like check-var

nha14:06:48

Thanks I will dig into it. Those can do "normal" testing as well right ? ie. not generative testing

minimal14:06:51

You can s/fdef before. The docs say the instrument fns are idempotent

nha14:06:57

Thanks 😄

nha14:06:29

Aah I read that but assumed it meant it can be called many times

nha14:06:16

Any reason the :ret has been removed ? Will it come back at some point ?

nha15:06:31

So it looks like clojure.spec.test is only for generative testing, I still have to use whatever I was using if I want to explicitly give input arguments to the tested function (ex. for things too hard to generate). Correct ?

gfredericks15:06:17

nha: sounds right

arohner20:06:07

FYI, I’m reliably reproducing the ’no such var encore/bytes?’ thing that @seancorfield reported the other day

arohner20:06:27

I don’t understand the cause, but I’m experiencing the same behavior

seancorfield21:06:24

There's an updated Encore that fixes that. Some interaction with cljx / do / defn in that case - and conflicting with a (new) core function.

seancorfield21:06:02

But I also eliminated every single dependency conflict and that solved the other, similar problems I had after that.

seancorfield21:06:21

So I'm not sure what the root cause is at this point.

arohner21:06:25

I’m hoping the clojure bug gets fixed

arohner21:06:49

is there a way to re-use fdef or fspec on other functions?

arohner21:06:57

I’d like to say “these two defns have the same fnspec"

arohner21:06:15

ah, looks like I can just (s/def ::name (s/fspec)) (s/def ::foo ::name)

bbloom21:06:28

@arohner: if two functions have the same fspec, wouldn’t they just be the same function? (or your fspec contains no interesting properties?)

arohner21:06:13

@bbloom no, there are lots of things that have the same spec that are interesting

arohner21:06:19

i.e. simple math

arohner21:06:29

+, *, - all take two numbers, return a number

arohner21:06:43

in this case, parsing

arohner21:06:53

take some input, return a parsed value and the rest of the stream

bbloom21:06:22

seems like you’d want to reuse a spec for args and result, but a different spec for the property relating args to results

bbloom21:06:46

there might be a missing abstraction here

bbloom21:06:21

we’ve got specs for data and specs for functions which contain arg spec, return spec, and relation spec, but we don’t have a spec for args + return (signature?) without relation

arohner21:06:34

yes, I’d like to get more specific in the future

arohner21:06:57

and I still have an open challenge out to “correctly” spec clojure.core/map

arohner21:06:14

I assert it can’t reasonably be done right now

bbloom21:06:20

correctly = ?

arohner21:06:43

‘map takes a fn of type X -> Y, and a seq of X, and returns a seq of Y'

bbloom21:06:15

ah yeah, spec lacks logic variables

bbloom21:06:22

can’t do context sensitive parsing

eggsyntax21:06:42

@arohner: how could you verify that it’s a fn of type X -> Y in a language that doesn’t do type declaration?

eggsyntax21:06:09

Is it sufficient to hand it an X, designate whatever comes out as Y, and then go from there?

arohner21:06:36

well, I can spec that f is X->Y now, and spec that coll is coll-of X

eggsyntax21:06:10

Makes total sense; somehow I was assuming f was unspecced.

arohner21:06:18

but that doesn’t narrow down map’s return spec

arohner21:06:34

because map’s spec is just seq or whatever

zpinter23:06:58

hello everyone! wondering if anybody knows of a clean way to define the spec for a map and its keys without having to repeat the list of keys again for the map spec

zpinter23:06:27

my first attempt was something like this:

(def style-keys
   [
    (s/def ::padding ::dimen-spec)
    (s/def ::padding-left ::dimen-spec)
    (s/def ::padding-right ::dimen-spec)
    (s/def ::padding-top ::dimen-spec)
    (s/def ::padding-bottom ::dimen-spec)])

(s/def ::style (s/keys :opt style-keys))

zpinter23:06:51

however, s/keys doesn't seem to like having :opt passed as a symbol (presumably since it's a macro)

zpinter23:06:20

this version compiles and works fine

(s/def ::padding ::dimen-spec)
(s/def ::padding-left ::dimen-spec)
(s/def ::padding-right ::dimen-spec)
(s/def ::padding-top ::dimen-spec)
(s/def ::padding-bottom ::dimen-spec)

(s/def ::style (s/keys :opt [::padding ::padding-left ::padding-right ::padding-top ::padding-bottom]))

zpinter23:06:55

however, every time I add a new key, I have to update two different places (which I'd ideally like to avoid in this case, since there'd be a lot of keys)

bbloom23:06:47

zpinter: i’m far from an expert (i haven’t tried spec properly yet) but i think you can just use s/and, right?

zpinter23:06:48

the recommendation from #C03S1L9DN was to make my own macro, which seems like a good approach, just wondering there was anything built-in

bbloom23:06:15

oh, nvmd, i think i misunderstood what you were asking for

bbloom23:06:21

but yeah, i’d guess making your own macro is the way to go - but depending on what you’re doing, the redundancy might make sense in order to allow decomposition later

bbloom23:06:32

for example, you may want to limit the styles on some thing to only color related styles or only spacing styles or what not

bbloom23:06:21

so you’d do (s/def ::padding…, (s/def ::padding-left ... and then group those with s/and to form ::padded

bbloom23:06:43

then you can have (s/def style (s/and ::padded ::colored ::etc-etc-etc

zpinter23:06:22

hmm... does s/and work with s/keys?

zpinter23:06:49

I guess you could use s/and to combine multiple (s/keys :opt values....

bbloom23:06:52

i’d be surprised if it doesnt, but like i said - i haven’t installed the alpha yet to try it 😛

zpinter23:06:43

will keep investigating, thanks @bbloom

eggsyntax23:06:07

@zpinter: I'd be interested in seeing what you come up with 🙂