Anyone have insight into why the such-that
is used here?
https://github.com/clojure/spec.alpha/blob/spec.alpha-0.2.176/src/main/clojure/clojure/spec/gen/alpha.clj#L187
Our tests are occationally failing with "Couldn't satisfy such-that predicate after 10 tries.", and the associated pred is :pred #object[clojure.core$ratio_QMARK_ 0x62fb2f00 "clojure.core$ratio_QMARK_@62fb2f00"]
.
there is some mention of such-that failures in gary fredericks' generators video at around 16:16 -- https://www.youtube.com/watch?v=F4VZPxLZUdA
ratios are conceptually goofy because you may or may not want to consider integers to be ratios in a given context
it's useful to think of integers as special kinds of ratios, because almost any use case for ratios should almost certainly apply to integers as well. It's hard to do arithmetic with ratios without bumping into integers inadvertently at least (e.g., (* 3/4 4/3)
)
but arguably it would surprise people if (ratio? 42)
returned true, so it doesn't; maybe there are other good reasons for this too beyond just surprise
in any case, there's a mismatch because test.check takes the first approach, but ratio?
wearing its spec hat obviously has the same semantics as ratio?
wearing its predicate hat, and so when you generate from it you don't want to generate integers
I think (such-that ratio? (ratio))
could definitely be improved; setting a higher retry threshold would stop the exceptions, but a custom generator would be the best; something like (gen/let [[n d] (gen/tuple gen/large-integer gen/large-integer)] (let [r (/ n d)] (if (ratio? r) r (/ (inc n) d))))
there might be some arithmetical edge case there I'm not thinking of, but I think that works
also I forgot to handle (zero? d)
Thanks for that! I thought I was losing my mind.
Perhaps spec'ing on rational?
is the way I should go.