Fork me on GitHub
Chris Lester02:03:33

does anyone have examples of a clojure spec for a vector holding heterogeneous elements? something like [[:rule-a :container {1 2 3 4]] [:rule-b :container [1 2 3 4] {:update "data"}][:rule-c :container {:create-data "stuff"}]], i.e., somewhat similar to a pldb fact DB ... I have specs for all the underlying rules but unsure how to get spec the overall vector of vectors without relaxing the spec back to "contains vectors". (s/def ::ruleset (s/coll-of (or ::rule-a ::rule-b))] isn't the right approach for sub-vectors. Not terribly surprising really, since it is an or of vector shapes, not keywords.


@activeghost s/cat is a spec for a heterogeneous sequence of values... maybe that will do what you need?


You normally see it for s/fdef for function argument lists, but it can spec data structures too.

Chris Lester02:03:34

Thx @seancorfield ... that's what I was looking for (and obvious when you said it). I should get some sleep lol. Thx.

Chris Lester03:03:27

...followup -- that actually doesn't work. It does work for "placed" arguments in a vector (I use s/cat for the definition of the rules themselves) if I had an order to the collection of vectors that would work.


@activeghost I thought you said you couldn't just do s/coll-of so I assumed there was some sort of ordering needed?


Maybe multi-specs would help here? Then have a collection of those... assuming you could describe the full range of subvectors as a single multi-spec? (which looks likely based on the example you showed)

Chris Lester05:03:31

Yes, can't do s/coll-of because it's a heterogeneous collection .. unless (s/coll-of ::spec-a ::spec-b ::spec-c) chooses to apply one of them based on the data (which it doesn't in my testing). I was looking at multispec's, looked like they were for multimethod's ... but can try those. Almost feels like Rich H. felt like this is over spec'ing the data given how difficult it is to say "this is a vector with N items of possibly N different shapes in it"


Multi-specs just happen to use multi-methods but if you have a way to discriminate the various N different shapes through a simple function (`first` looks like a good candidate based on your examples?), then (s/coll-of ::my-multi-spec) is what you'd end up with


And ::my-multi-spec would discriminate down to all the individual specs you already have.

Chris Lester06:03:57

After some playing around and making the multi-spec an anon fn got it working (s/with-gen #(s/multi-spec pred? %) ...) with the multimethod def being (defmulti pred? second).


I would guess it's supposed to be meta


The ns docstring is helpful here


Ah, right. The error was in some other place. And being dumb enough, I checked the GitHub sources instead of checking the actual ones that I use.