-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add schpec.number #1
base: master
Are you sure you want to change the base?
Conversation
|
||
(s/def ::real | ||
(s/spec real? | ||
:gen #(gen/double* {:infinite? false :NaN? false}))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this spec/pred intended to apply just to doubles? If so, I would use a name closer to "double" or "floating-point", and check that it's an instance of Double
in the predicate; I personally don't like the name "real" for numeric types because of the mismatch with the mathematical term.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it's intended to apply to all real number values, which as far as I can reason, include all things clojure considers numbers except these three corner cases. I confess, I don't see any mismatch between this predicate and the mathematical domain of real numbers. Is it because there are irrational numbers (e.g. pi) that don't have precise representations?
Clojure core already provides double?
. My intent here is to provide predicates and specs for numbers in terms of their domain (e.g. real numbers, numbers that can be precisely represented as decimals with such and such precision), not their actual types.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what do you think about the name finite?
for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, irrational numbers are the sort of thing I'm thinking of w.r.t. the word "real"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll mull over finite?
. Note of course there are plenty of real, irrational numbers that do pass this predicate: (/ 1 3)
and friends. It's not pi's fault that clojure doesn't have an e.g. Taylor series expansion type to compute it to arbitrary precisions :)
If the predicate failed to cover such a case, I'd buy the argument that it's not named correctly. But AFAICT, it covers all real numbers expressible in clojure's arithmetic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand this comment fully; (/ 1 3)
looks like a rational.
example tests would definitely be good here; does "clojure.spec.test exercises" refer to just running the generator a bunch to make sure it doesn't crash? |
thanks for the PR by the way; I intend to keep the namespace the same as I appreciate the convention of following DNS naming so we don't have to worry about our libraries colliding. In fact I'm tempted to ask that you move this down to |
:max max})))))] | ||
(s/spec pred :gen gen)))) | ||
|
||
(s/def :specs.number.decimal/precision |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you're putting these in a different namespace to distinguish them from the user-facing specs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, they're not intended as published specs for general use, they're just to support the s/keys :opt-un. I've tried a few different techniques for bespoke options specs and haven't really found anything I like better than this yet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's interesting, and it raises the question of how users are going to be discovering available specs; if they just rely on our documentation, then this isn't a concern.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would use bare keys here
(s/def ::plugin-item
(s/and
(s/cat :lib-name symbol?
:version-str non-blank-string?
:dependency-item-args
(s/* (s/alt :optional (s/cat :ky #{:optional}
:val boolean?)
:scope (s/cat :ky #{:scope}
:val ::name-like)
:classifier (s/cat :ky #{:classifier}
:val ::name-like)
:native-prefix (s/cat :ky #{:native-prefix}
:val (some-fn string? symbol? keyword?))
:extension (s/cat :ky #{:extension}
:val (some-fn string? symbol? keyword?))
:exclusions (s/cat :ky #{:exclusions}
:val ::exclusions)
:plugins-args (s/cat :ky #{:middleware :hooks}
:val boolean?))))))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems strange to register keys that are just argument keys, they are not global types or contracts...
@gfredericks I revised the semantics and names in response to the comments: namely, I renamed real to finite and switched decimal-in to bigdec-in and enforce the bigdec type. I can also change the ns if you would prefer. |
Double/POSITIVE_INFINITY false | ||
Double/NEGATIVE_INFINITY false | ||
Double/NaN false | ||
true))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this case
statement works; could you add tests?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Absolutely
yes, |
|
||
(s/def :specs.number.bigdec/max | ||
(s/and bigdec? | ||
::finite)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer a naming convention for these specs that's actually scoped to com.gfredericks.schpec
; I suppose a subnamespace would work best: :com.gfredericks.schpec.numbers.bigdec-in/max
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, sorry, holdover from my personal project. It's fixed, and there's a
trivial example test for it.
Would we like to see clojure.spec.test/stest exercises in the tests?
On Sun, Aug 7, 2016 at 12:33 PM, Gary Fredericks [email protected]
wrote:
In src/com/gfredericks/schpec/number.clj
#1 (comment):
(s/spec pred :gen gen))))
+(s/def :specs.number.bigdec/precision
- pos-int?)
+(s/def :specs.number.bigdec/scale
- (s/spec (fn [x](and %28int? x%29 %28not %28neg? x%29%29))
:gen #(gen/large-integer\* {:min 0})))
+(s/def :specs.number.bigdec/min
- (s/and bigdec?
::finite))
+(s/def :specs.number.bigdec/max
- (s/and bigdec?
::finite))
I'd prefer a naming convention for these specs that's actually scoped to
com.gfredericks.schpec; I suppose a subnamespace would work best:
:com.gfredericks.schpec.numbers.bigdec-in/max.—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/gfredericks/schpec/pull/1/files/9b4096f665b827eac7843e8fb77e41f9c3705d4c#r73805035,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAAx2zx1Z3X-p_6uICJ_YoTi9gpvjhVqks5qdgjmgaJpZM4JRIaK
.
There's that simple test. I can add more tests in a couple of hours, particularly using stest/check on bigdec-in, but I'm heading to the gym rn tho. |
|
||
(s/def ::finite | ||
(s/spec finite? | ||
:gen #(gen/double* {:infinite? false :NaN? false}))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you intend this to be just Doubles or other numeric types as well? The generator implies the former while the predicate implies the latter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question. If we wanted the latter, we'd need to choose the generator from, what, longs, doubles, bigdecs, bigints? Would that be sufficiently broad, or would we want shorts and ints and floats also?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ratios too probably
I realized after our conversations a couple weeks ago that a big reason I don't see a lot of utility in specs that combine exact and inexact types is that normal equality doesn't work; e.g., (not= 42 42M)
and (not= 42M 42.0)
. So I see the natural classes of numeric types as:
- fixed-integer < arbitrary-integer < ratio(including integers)
- bigdec
- doubles
where any of those five are natural classes to spec out, but combining those three categories is rather less useful.
So all that to say, I think restricting this to doubles makes a lot more sense.
Of course this gets a lot more muddled when we consider clojurescript :/
I am into that, but now we're back to the question of names: what do we call I'd be into dropping it, except for the fact that in literally every production repo I've introduced spec to, I've written this spec. |
|
Note if you're really gonna take this ball and run with it - which is awesome - a shorter ns might be nice. Personally, I'd be cool with schpec as the top level.
Curious what testing approaches you think might be good. Examples and clojure.spec.test exercises?