Fork me on GitHub
Ben Hammond07:06:03

I am calling generate on a complex data structure. Sometimes I see this error. I would normally troubleshoot this by commenting out parts of the spec to zone in on the problem; but I'm wondering if there is a smarter way to debug generators

Ben Hammond07:06:18

is there a direct way to dicover the specific sub-spec that has the problem?

Ben Hammond09:06:12

okay another question; I want a generator that has two modes of operation • when there is data available in the dynamc variable *existing-ids* then I want it to behave like (element *existing-ids)` • when *existing-ids* is empty then I want it to behave like (spec/gen string?) this must be a fairly common use case how has it been solved before?

Ben Hammond09:06:09

I'm thinking something like

  (test.gen/return nil)
  (fn [_]
      (if (not-empty *existing-ids*)
        (test.gen/elements *existing-ids*)

Ben Hammond10:06:28

that doesn't seem a very smart solution though

Ben Hammond10:06:34

I think that's the best I can do, unless I hack directly into

(defn- bind-helper
(defn- make-gen
but that doesn't seem like a very good idea either

Ben Hammond10:06:07

(def ^:dynamic *existing-ids* nil)
=> #'dev/*existing-ids*
(def gg (test.gen/bind
          (test.gen/return nil)
          (fn [_] (if (not-empty *existing-ids*)
                    (test.gen/elements *existing-ids*)
=> #'dev/gg
(spec.gen/generate gg)
=> "9Dlv2SuFqT4Jb"
(binding [*existing-ids* [:this :that :tother]]
  (spec.gen/generate gg))
=> :that

Ben Hammond10:06:20

I suppose I could store the test.gen/elements in the *existing-ids* var

Ben Hammond10:06:05

(spec/with-gen takes a gen-fn, and I'd hope that I could use this to choose between generators, but of course it doesn't get called very often

Ben Hammond10:06:32

this might be better actually

(defn build-indirect-gen 
    (test.gen/return nil)
    (fn [_] (deref vargen))))

(def ^:dynamic *existingids-gen* test.gen/string-alphanumeric)
(def gg (build-indirect-gen #'*existingids-gen*))

(binding [*existingids-gen* (test.gen/elements [:this :that])]
  (test.gen/generate gg))
=> :that 

(test.gen/generate gg)
=> "Sjeu5IwBWbMUZl"


@ben.hammond afair, Gary touched on it debugging "Couldn't satisfy such-that predicate after 100 tries" here:

👍 4

this is the timestamp

Ben Hammond15:06:42

I've not seen that video. that's very interesting

Ben Hammond16:06:46

i'd not seen the size/scale explained properly before

Ben Hammond16:06:57

I'd assumed they represented mean/standard deviation

Alex Whitt18:06:54

I'm sure this has been asked and answered, but I can't find the answer... Why can I not do the following?

(s/def ::a any?)
(s/def ::thing (let [ks [::a]] (s/keys :req ks)))
That yields Don't know how to create Iseq from: clojure.lang.Symbol.

Alex Whitt18:06:51

I'm guessing that macros are the only way to dynamically define specs?


pretty much


I think spec2 has some improvements to this, but still isn't going to let you plop a let in there


I think spec2 will expose a public ast-like interface for programmatic spec creation/manipulation of specs as data


but the surface syntax will still be macros

Alex Whitt18:06:38

Hmm, alright. I'm interested in the spec2 feature you mentioned so I'll take a look. Thanks!


Spec 2 has a macro layer and a function layer that implements the macros. You can programmatically construct pretty much any spec in Spec 2.


(we have a branch of our code base at work that uses Spec 2 -- so we can track the sort of differences we'll need to make when we transition from Spec 1)

Alex Whitt13:06:58

Ah, that's exciting!