clojure-spec

About: http://clojure.org/about/spec Guide: http://clojure.org/guides/spec API: https://clojure.github.io/spec.alpha/clojure.spec.alpha-api.html
Eddie 2020-01-03T03:42:44.072700Z

@seancorfield I spent some time today with spec 2. It seems like it's design goals are exactly what I need. I attempted to migrate and it was pretty rough (not complaining, I totally understand that it is still in development and also a new major version so I expected many breaking changes). I am not sure if we will be jumping on board with spec 2 yet, but thank you for the pointer!

Eddie 2020-01-03T03:46:18.074900Z

There are a few things that we are doing in spec 1 that I cannot figure out how to recreate in spec 2, even though it smells like it should be possible. For example, I would like to implement a custom generator that simply pulls a random element from a set. I can get this to work if the set satisfies (every? constant-val? ...) but otherwise, I cannot.

alexmiller 2020-01-03T03:53:28.075400Z

are you using a set spec?

alexmiller 2020-01-03T03:56:16.076200Z

user=> (s/def ::s #{1 2 3})
:user/s
user=> (gen/sample (s/gen ::s))
(2 1 3 2 2 1 1 1 2 2)

alexmiller 2020-01-03T03:58:44.077400Z

if you're trying to do this outside s/def (which has some magic), you can do something like

user=> (gen/sample (s/gen (s/resolve-spec #{1 2 3})))
(1 2 1 1 3 1 3 3 1 1)

alexmiller 2020-01-03T04:00:20.078400Z

one of the caveats you might be seeing is that set specs are constrained to constant values only which is part of the new symbolic spec direction

alexmiller 2020-01-03T04:01:52.079Z

there are a couple of options but you can just use the built-in generators directly if you have something else

Eddie 2020-01-03T17:08:11.083300Z

Thank you! gen/elements is exactly what I was looking for. However I am running into some strange behavior on the with-gen .

user=> (s/with-gen (s/spec int?)
                   (fn [] (gen/elements [-1 0 1])))
Execution error (IllegalArgumentException) at clojure.alpha.spec.protocols/eval190$fn$G (protocols.clj:11).
No implementation of method: :with-gen* of protocol: #'clojure.alpha.spec.protocols/Spec found for class: clojure.lang.PersistentList

user=> (s/exercise (s/with-gen int? (fn [] (gen/elements [-1 0 1])))
            10)
([-1 -1] [0 0] [1 1] [-1 -1] [-1 -1] [-1 -1] [0 0] [1 1] [-1 -1] [1 1])
Neither of those seem right to me. Am I missing a change from Spec 1?

alexmiller 2020-01-03T17:14:50.084400Z

yeah, seems fishy. I'd expect the first one to work

alexmiller 2020-01-03T04:02:02.079400Z

user=> (def a 1) (def b 2)
#'user/a
#'user/b
user=> (gen/sample (gen/elements [a b]))
(1 2 2 2 1 2 2 2 2 2)

A.J. Gardner 2020-01-03T16:40:52.082300Z

hello! it seems like @rafael and I ran into the same issue. I posted about it in the google group: https://groups.google.com/d/topic/clojure/rcuWmqyGWzs/discussion my specs:

(s/def ::id int?)
(s/def ::tag-id ::id)
(s/def ::child-tag ::tag-id)
(s/conform ::child-tag 22)
;; 22
(s/conform ::child-tag "a")
;; :clojure.alpha.spec/invalid
(s/conform (s/schema [::child-tag]) {::child-tag 22})
;; Execution error (IllegalArgumentException) at clojure.alpha.spec.protocols/eval1458$fn$G (protocols.clj:11).
;; No implementation of method: :conform* of protocol: #'clojure.alpha.spec.protocols/Spec found for class: clojure.lang.Keyword
(s/conform (s/schema [::tag-id]) {::tag-id 22})
;; Execution error (IllegalArgumentException) at clojure.alpha.spec.protocols/eval1458$fn$G (protocols.clj:11).
;; No implementation of method: :conform* of protocol: #'clojure.alpha.spec.protocols/Spec found for class: clojure.lang.Keyword
(s/conform (s/schema [::id]) {::id 22})
;; #:foo{:id 22}

A.J. Gardner 2020-01-03T16:44:14.082800Z

and the stack trace, just in case that’s useful:

(clojure.repl/pst)
IllegalArgumentException No implementation of method: :conform* of protocol: #'clojure.alpha.spec.protocols/Spec found for class: clojure.lang.Keyword
	clojure.core/-cache-protocol-fn (core_deftype.clj:583)
	clojure.core/-cache-protocol-fn (core_deftype.clj:575)
	clojure.alpha.spec.protocols/eval1458/fn--1556/G--1439--1567 (protocols.clj:11)
	clojure.alpha.spec.impl/schema-impl/reify--2753 (impl.clj:435)
	clojure.alpha.spec/conform (spec.clj:245)
	clojure.alpha.spec/conform (spec.clj:237)
	clojure.alpha.spec/conform (spec.clj:241)
	clojure.alpha.spec/conform (spec.clj:237)
	foo/eval6028 (form-init13722384443750232197.clj:1)
	foo/eval6028 (form-init13722384443750232197.clj:1)
	clojure.lang.Compiler.eval (Compiler.java:7177)
	clojure.lang.Compiler.eval (Compiler.java:7132)

alexmiller 2020-01-03T16:50:40.083200Z

yeah, this is just a bug in spec

Eddie 2020-01-03T17:08:11.083300Z

Thank you! gen/elements is exactly what I was looking for. However I am running into some strange behavior on the with-gen .

user=> (s/with-gen (s/spec int?)
                   (fn [] (gen/elements [-1 0 1])))
Execution error (IllegalArgumentException) at clojure.alpha.spec.protocols/eval190$fn$G (protocols.clj:11).
No implementation of method: :with-gen* of protocol: #'clojure.alpha.spec.protocols/Spec found for class: clojure.lang.PersistentList

user=> (s/exercise (s/with-gen int? (fn [] (gen/elements [-1 0 1])))
            10)
([-1 -1] [0 0] [1 1] [-1 -1] [-1 -1] [-1 -1] [0 0] [1 1] [-1 -1] [1 1])
Neither of those seem right to me. Am I missing a change from Spec 1?

A.J. Gardner 2020-01-03T17:10:43.083600Z

whew

alexmiller 2020-01-03T17:14:50.084400Z

yeah, seems fishy. I'd expect the first one to work