This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-01-17
Channels
- # aleph (2)
- # announcements (20)
- # aws (43)
- # aws-lambda (5)
- # babashka (9)
- # beginners (231)
- # calva (4)
- # cider (12)
- # cljdoc (8)
- # cljsrn (3)
- # clojure (47)
- # clojure-europe (5)
- # clojure-nl (4)
- # clojure-spec (41)
- # clojure-uk (47)
- # clojuredesign-podcast (3)
- # clojurescript (20)
- # cryogen (3)
- # cursive (4)
- # data-science (2)
- # datomic (15)
- # emacs (4)
- # fulcro (21)
- # jackdaw (6)
- # jobs (1)
- # joker (13)
- # juxt (8)
- # kaocha (10)
- # malli (7)
- # off-topic (29)
- # pathom (11)
- # re-frame (19)
- # reagent (3)
- # reitit (26)
- # remote-jobs (8)
- # schema (2)
- # shadow-cljs (112)
- # spacemacs (1)
- # tools-deps (49)
- # vim (2)
- # xtdb (7)
Is there any way of relating a neighboring spec's value into the :count
option of s/every
?
you need to s/and with a predicate that can do that at the containing level
okay, I have something like this
(s/def :ctx/region
(s/and (s/keys :req [:ctx/width
:ctx/slots])
#(= (count (:ctx/slots %))
(:ctx/width %))))
this is true of any data with internal constraints like this. the general strategy is to use gen the width first, then use a combination of fmap and bind to generate the slots and assemble into the map
you might also ask what the width is buying you in this data structure when it is the same as the count of the slots
(and as an aside, I find that pushing on data that is hard to spec often improves the shape of the data and the code that uses it)
My idea was to have a degree of "memoization" or redundancy baked into the data structure - in this case slots
may be a lazy sequence that is generated on demand, so I don't want to keep calling count
on it unnecessarily
of course this introduces the risk of width
getting out of sync with the data, which is why I'm using spec to assert the constraints during dev time
fair enough
there are a few other "derived" keys similar to this that I'm storing in the same data structure, just wondering if this isn't considered a code smell?
Here's my best attempt at that generator:
(s/def :ctx/width (s/int-in 1 11))
(s/def :ctx/slot string?)
(s/def :ctx/slots (s/coll-of :ctx/slot))
(s/def :ctx/region
(s/and (s/keys :req [:ctx/width
:ctx/slots]
:gen #(let [w (gen/generate (s/gen :ctx/width))]
(gen/hash-map
:ctx/width (s/gen #{w})
:ctx/slots (s/gen (s/coll-of :ctx/slot
:count w)))))
#(= (count (:ctx/slots %))
(:ctx/width %))))
you don't want to use gen/generate in there - that will foil the test.check shrinking mechanisms
instead, use gen/bind with (s/gen :ctx/width) and the gen/hashmap you have
gen/bind lets you make a generator on a generator
got it, thanks so much for the help!
#(gen/bind (s/gen :ctx/width)
(fn [w]
(gen/hash-map
:ctx/width (gen/return w)
:ctx/slots (s/gen (s/coll-of :ctx/slot :count w)))))
Let’s say I have a Datomic query and I want to find all the variables defined in that query. Would spec be a good tool to bring to bear on that problem?
@zane I'm not saying it couldn't be done but I certainly wouldn't expect to use Spec for such a problem.
Even if you wrote a complete Spec of Datomic queries, if you s/conform
it so it "identifies" the ?
variables, you'd still have to walk the resulting data structure to extract them all -- you might just as well walk the original Datomic query.
I believe there are specs of Datomic's query syntax out there btw, don't have any links handy (but I agree that I probably wouldn't pick that as the first approach)
Is it fair to say that conform
is not really suited to these kinds of problems in the general case?
conform
is not designed for parsing or general transformation, if that's what you're asking?
conform
is intended to "tag" the resulting data with "how" the data conformed to the Spec, so downstream code can behave accordingly.
Isn’t that kind of tagging exactly what I’m after in this case? I’m not sure I’m understanding the details here.
You'd still have to walk the result to find the tagged values tho
I guess I’m still struggling with which kinds of “parsing” are appropriate to do with spec and which aren’t.
Differentiating between different shapes of data seems like something you could achieve with it via s/or
and s/conform
.
That's not to say that some people don't (ab)use Spec to do some amount of parsing and transformation... cough ...but that's not what it was designed for: coercion is somewhat of a "side-effect" of conforming, you might say 🙂