This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-11-09
Channels
- # bangalore-clj (1)
- # beginners (158)
- # boot (8)
- # cider (9)
- # cljsjs (9)
- # clojure (169)
- # clojure-austin (1)
- # clojure-denmark (1)
- # clojure-dusseldorf (5)
- # clojure-italy (9)
- # clojure-losangeles (2)
- # clojure-russia (31)
- # clojure-spec (53)
- # clojure-turkiye (1)
- # clojure-uk (56)
- # clojurescript (145)
- # cursive (72)
- # datascript (4)
- # datomic (3)
- # duct (121)
- # events (9)
- # figwheel (1)
- # fulcro (46)
- # graphql (4)
- # hoplon (16)
- # jobs (1)
- # jobs-discuss (4)
- # leiningen (16)
- # lumo (5)
- # off-topic (38)
- # om (1)
- # om-next (5)
- # onyx (104)
- # parinfer (5)
- # re-frame (106)
- # reagent (1)
- # ring-swagger (3)
- # rum (1)
- # shadow-cljs (235)
- # slack-help (4)
- # unrepl (25)
- # yada (9)
I think I’ve found a bug in clojure 1.9 / clojure.core.specs.alpha:
(if-let [foo 1] foo :clojure.spec.alpha/invalid)
CompilerException clojure.lang.ExceptionInfo: Call to clojure.core/if-let did not conform to spec:
In: [2] val: :clojure.spec.alpha/invalid fails at: [:args :else] predicate: any?
#:clojure.spec.alpha{:problems ({:path [:args :else], :pred clojure.core/any?, :val :clojure.spec.alpha/invalid, :via [], :in [2]}), :spec #object[clojure.spec.alpha$regex_spec_impl$reify__1188 0xeabf22e "clojure.spec.alpha$regex_spec_impl$reify__1188@eabf22e"], :value ([foo 1] foo :clojure.spec.alpha/invalid), :args ([foo 1] foo :clojure.spec.alpha/invalid)}, compiling:(*cider-repl catalyst-graft*:8654:1)
issue appears to be that you can’t return the value :clojure.spec.alpha/invalid
from macros. It’s kinda like a macro hygiene issue, but for s/invalid
cool. Figured it would be
thanks
Hello everyone, I am learning Spec'ing higher order functions. Here are the examples which I am experimenting with (actual HOFs I am working on are quite complex) :
(Works fine with exercise-fn.)
(defn hof1 [x f] (f x))
(s/fdef hof1
:args (s/cat :x number?
:f (s/fspec :args (s/cat :y number?)
:ret number?))
:ret number?
:fn #(= ((-> % :args :f) (-> % :args :x)) (:ret %)))
(exercie-fn doesn't work :(. Here I am expecting input f to be either + or - or * fn.)
(defn hof2 [f x] (f x 1))
(s/fdef hof2
:args (s/cat :x number?
:f (s/fspec
:args (s/cat :y number?)
:ret number?))
:ret number?
:fn #(= ((-> % :args :f) (-> % :args :x) 1) (:ret %)))
How write spec to ensure correctness in the samples generated using exercise-fn for HOFs? (I want to use spec's check fn to test HOFs on generated inputs based on written spec.)Hi, I’m a spec noob here — can somebody tell me an easy way to automatically (st/instrument)
in all namespaces?
you only need to call st/instrument once
but you have to make sure you’ve loaded all the namespaces before you do
if it’s in your dev setup, just call st/instrument in your main or dev namespace at the bottom
if it’s in tests, your best bet is probably to use a fixture
@joost-diepenmaat Ah OK, thanks!
Also, how do I generally make “did not conform to spec” errors easier to read? I’m using Orchestra+Expound and have specified the following, but to no avail:
(st/instrument)
(set! s/*explain-out* expound/printer)
as mentioned here: https://github.com/bhb/expound#using-orchestra@kumarshantanu Can you post an example of the code you’re calling and the “did not conform to spec” message you get?
Setting expound/printer
seems to work for me https://gist.github.com/bhb/f538f2b1a47eb7a1514da0fe62d46265
This gist works for me at the REPL. @bbrinck The error reporting I’m dealing with extracts the exception message and stack trace and sends it as HTTP response. Is Expound supposed to work in that use case?
Yes, it should. For instance, building on my previous example, here is code to catch the instrumentation exception and return the message as a string: (try (foo "") (catch Exception e (.getMessage e)))
Another option is to use Expound to validate incoming data directly. For instance, let’s say the HTTP endpoint takes some JSON as incoming data
Then you could validate that data with something like:
(binding [s/*explain-out* expound/printer]
(s/explain-str :my-app/http-data-spec http-data))
By default, Expound writes out all the Clojure specs that failed, but there is an (undocumented, but soon to be documented) option to omit this
If anyone else is interested, the issue was the dynamic var *explain-out*
is only set in the current thread, and servers like HTTP Kit spawn new threads for requests. The fix is to replace (set! s/*explain-out* expound/printer)
with (alter-var-root #'s/*explain-out* (constantly expound/printer))
there a better way of having a generator that just executes a function with no regard to the input? this does what i want, but notice the argument here is unnecessary #(gen/fmap (fn [_] (utils/uniform 1e12 1e13)) (s/gen pos-int?))
I was going to suggest gen/return
but do you even need the output of the pos-int?
generator?
for example, doesn’t matter what the previous generator is doing if you’re just constantly returning the same thing regardless of input
(gen/sample (gen/fmap (constantly -1) gen/pos-int))
=> (-1 -1 -1 -1 -1 -1 -1 -1 -1 -1)
this is a nonstandard generator construction The "right way" would be to use combinators somehow rather than calling a function that supplies its own randomness. That might be a bit more effort, depending on what you want. If you aren't doing things the "right way", then there's not really a better way.
do you really need a uniform distribution between two doubles?
(gen/double* {:min 1e12 :max 1e13})
would not be very nonuniform I don't think
@U3DAE8HMG yeah my point was i didn’t need the output of the pos-int? generator. gen/return
was EXACTLY what i was looking for, thanks 😉
@U0GN0S72R yeah i need uniform distribution between two large numbers because made a spec that expected a number beteween those two ranges and this issue causes it to fail without a custom generator https://dev.clojure.org/jira/browse/CLJ-2179
that ticket is interesting
@U0DHHFEDP what is your spec for exactly?
I'm having trouble seeing why something would fail
@U0GN0S72R it’s a ghetto spec for a unix timestamp in ms, the generator fails because it attempts to make ints starting at very low numbers. here’s the code
(s/and pos-int?
(s/int-in 1e12 1e13))
it passes most the time when ran by itself but i have it nested in another datastructure and it fails 100% of the time
oooooh; this is an s/and
issue, not an s/int-in
issue
if you swap the order of those two you should have it succeed
or set the generator to be the default generator that the s/int-in
expression generates
I think CLJ-2179 is a red herring here
i think the issue is legit, if you try running the code (gen/sample (s/gen (s/int-in 0 100)))
you get a ton of low numbers
my final code works well enough though (s/with-gen (s/and pos-int? (s/int-in 1e12 1e13)) #(gen/choose 1e12 1e13) ))
@U0DHHFEDP getting low numbers that are in the range is one thing, but I thought you were describing getting numbers that were out of range
@U0GN0S72R that’s what I thought was going on, i think my issue is that i was plugging in doubles using the short notation. It seems (s/int-in) doesn’t cast those for you but will verify that the input is in range, this is why I needed to pair it with pos-int
;; Fails reliably
(s/def ::test2 (s/and pos-int? (s/int-in 1e12 (- 1e13 1))))
;; Fails sometimes
(s/def ::test3 (s/and pos-int? (s/int-in 1e9 (- 1e10 1))))
(s/def ::works (s/int-in (encore/as-int 1e13) (encore/as-int (- 1e14 1))))
bumping the numbers up in the first example makes it fail a lot more often, I guess pos-int is the only thing generating numbers here?
in any case was my fault for plugging doubles in something that is clearly for ints 😉
yeah, when you use s/and
the generator is taken from the first spec and the remaining specs are used to filter