Fork me on GitHub

What's a good way to spec a sequence with a static subsequence? For example, if I want to spec a seq that contains 1, 2, 3 somewhere in the middle, is there a better way to do it than the following?

(s/conform (s/cat :pre (s/+ any?)
                  :one-two-three (s/& (s/+ any?) #(= [1 2 3] %))
                  :post (s/+ any?))
           [:foo :bar 1 2 3 :baz :qux])
This works, but it feels like I'm abusing s/&.

Alex Miller (Clojure team)05:03:09

@english doesn’t seem like you need the s/& at all

Alex Miller (Clojure team)05:03:01

(s/conform (s/cat :pre (s/+ any?)
                  :one-two-three (s/cat :1 #{1} :2 #{2} :3 #{3})
                  :post (s/+ any?))
           [:foo :bar 1 2 3 :baz :qux])

Alex Miller (Clojure team)05:03:27

not very pretty, but that should work a little more directly

Alex Miller (Clojure team)05:03:01

it will gen automatically too whereas the prior one will not


I started writing a Language Server for Clojure(Script)


(some background on what a language server is in the gh issue above)


naturally I want to leverage clojure.spec for this task


ie. if I have (defn x :foo) in a file or REPL I get an exception with Call to clojure.core/defn did not conform to spec and ex-data containing the usual information


that information however is not enough for me to provide good highlighting for the error that occurred since it contains no source information


the question is whether or not this is something the error should/could contain or not? I imagine all tools will require it somehow as the given exception doesn't tell you anything about the actual location of the error.


@alexmiller you said you were looking into the error presentation details a while back, any progress on that?


for now even just the form that caused the fdef to fail would be a start


found :clojure.spec/args but neither that list or the items in there contain any meta data from the reader


is it possible to use spec to generatively test stateful fns? for example, if I have a fn that takes an in and out core.async channel, where it performs some logic on the values in the in channel (when they show up in the future), and perhaps puts values on the out channel, can I generate any meaningful tests?


There are a few attempts it seems: and a neat resource from an Erlang implementation: , but I’ve been unable to dig up any recent available libs or discussions on the matter

Alex Miller (Clojure team)12:03:42

@thheller yeah I made some progress on it but got blocked by not having access to the root value in the explain-data. I have a ticket and patch pending about that and had a brief conversation about it with Rich last week. I believe there is a separate ticket re spec source meta, certainly there is some overlap with the idea of spec doc meta.


@alexmiller ah thx, found the JIRA issue. will try with the patch and see if I can do what I have in mind.


although it still doesn't contain the original form, only the args


should catch the ExceptionInfo the macroexpand-check will produce

Alex Miller (Clojure team)14:03:30

hmm, it used to but I think when macroexpand-check was refactored this didn’t get changed along with it

Alex Miller (Clojure team)14:03:45

macroexpand-check used to throw IllegalArg

Alex Miller (Clojure team)14:03:53

I will take a look at that

Alex Miller (Clojure team)14:03:13

should have been changed with this commit

Alex Miller (Clojure team)14:03:23

that’s definitely a bug

Alex Miller (Clojure team)14:03:24

so that happened in 1.9.0-alpha12


@alexmiller maybe we could add the last known form to CompilerException(String source, int line, int column, Throwable cause, Object form) as well


there are many places where a compiler exception is thrown and the form is known

Alex Miller (Clojure team)14:03:31

oh, that’s not there already. that needs to be a separate idea then.

Alex Miller (Clojure team)14:03:22

that needs some thought. when you’re throwing arbitrary data like that you can introduce some weird problems

Alex Miller (Clojure team)14:03:48

I have been burned by that a number of times over the years

Alex Miller (Clojure team)14:03:51

I hate that the only exception in Clojure that can attach location info is CompilerException… grr


hehe a 2nd constructor adding the form where possible seems like the simplest non-breaking change


not sure how the CLJ compiler/reader is implemented but if the form contains lazy things that will indead cause strange errors


I will attempt to port the clojure.core.specs over to CLJS soon, it would be amazing if the exceptions generated on errors where somewhat similar

Alex Miller (Clojure team)14:03:35

well when you have a form, it’s been read and should not be lazy (unless perhaps it was generated by a prior macro?)

Alex Miller (Clojure team)14:03:14

do you really want the form or do you want a string representation of the form?


the form with metadata would be perfect

Alex Miller (Clojure team)14:03:38

yeah, that’s what I was wondering


with that I can get the string if I need it


I have never actually worked with the Clojure analyzer, only the tools.analyzer or cljs.analyzer. so I need to figure out how the CLJ metadata looks


but I take everything I can get at this point

Alex Miller (Clojure team)14:03:14

well, nothing in this area is going to change quickly :)


hehe no doubt but the change to CompilerException is simple enough that I can try in a branch


and report if thats actually as useful as I think it is


forms can be very large, at the repl you just type (/ 1 0) and that fails, and it seems like a good idea to report the form, but I really have no need to see the macroexpansion of a 100 line go block


Say, is there any way to get (s/keys) to validate a map with non-namespaced keywords? Trying to add some validation around an external library I don't control


Oh, sorry, just noticed the section in the guide around :req-un, will read that more carefully


How does Transit intersect with Clojure Spec (if at all)?


i don't think it does directly


However, Transit is a great way to pass around namespaced keys, which is the norm for things used by clojure.spec