-
Notifications
You must be signed in to change notification settings - Fork 377
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
Defining Ord in terms of lt vs lte #239
Comments
You still need to check for |
In haskell Ord could be defined in terms of |
// two equals checks unless lte is defined in terms of gt
const lt = a => b => a.lte(b) && !a.equals(b); |
I think i didn't understand something. you have provided 3 alternative implementation of lte lt gt and gte. in all this 3 cases equals is used in 2 of functions. so what's the difference |
Unless |
so one should implement |
That was my second point in the OP. It's unnecessary indirection. |
@joneshf @davidchambers @scott-christopher any opinions? |
I don't follow your argument about efficiency, @gabejohnson. I may be missing something, but what @safareli wrote earlier seems right to me: by specifying I do, though, think that the implementations of This reads very nicely ( // lte :: Ord a => a -> a -> Boolean
const lte = x => y => x.lt(y) || x.equals(y); This is circuitous ( // lt :: Ord a => a -> a -> Boolean
const lt = x => y => x.lte(y) && !x.equals(y); Perhaps due to symmetry, this upsets me less than the above: // lt :: Ord a => a -> a -> Boolean
const lt = x => y => x.lte(y) && !y.lte(x); I'm not too worried about whether these implementations exactly match my mental model of what it means for one value to be less than or greater than another. We will define these functions once (in sanctuary-type-classes) and from that point forward only be concerned with the underpinnings ( I suggest that the next step is for one of us to open a pull request to add @gabejohnson, does the circuitous |
@davidchambers, the circuitous It might turn out that we won't end up defining |
I agree that it is presumptuous to assume someone will implement |
https://hackage.haskell.org/package/base-4.9.1.0/docs/Data-Ord.html
So we can add compare for efficiency reasons. btw in purescript default implementations are exported from the module where typeclass is defined. we currently do not export default implementations they exist only in readme.md. if we export those depending on FL will be much useful for library authors as it will also export default implementations which could be reused. will open Issue on this #240 |
We'd then need to specify Ordering with members |
We still specify result of |
@safareli from #235 (comment)
I think @joneshf has a point. If FL had an |
If we did add an |
Haskell's |
See #241 |
@safareli: RE Haskell (presumably GHC) asserting that |
Why |
@davidchambers It was a half-joking answer (though half-serious in the fact that null/bool checks are probably more performant than string comparisons) to @safareli's:
(i.e., there's only one built-in "type" with strictly three values, and that's the nullable boolean) If My two cents: I love the idea of FL exporting its derivations section (as well as a set of common related functions, e.g. the other comparators), and then the spec needn't grow to include anything more. |
Are you familiar with sanctuary-type-classes? I believe it serves exactly the role you have in mind, and @gabejohnson is working on a patch to add |
@davidchambers ... Today, you have legitimately and significantly improved my life. |
I don't really understand the root of the performance problem. I can take any Ord operator(lt, lte, gt, gte) and define the rest using only negation. // based on .lte
const lte = a => b => a.lte(b);
const lt = a => b => !b.lte(a);
const gt = a => b => !a.lte(b);
const gte = a => b => b.lte(a);
// based on .gt
const lte = a => b => !a.gt(b);
const lt = a => b => b.gt(a); // edit: before const lt = a => b => b.lte(a);
const gt = a => b => a.gt(b);
const gte = a => b => !b.gt(a); // edit: before const gte = a => b => !b.lte(a); |
@xgbuils your definitions are incorrect:
|
There's also an issue in that
I copied clause 1i from the Setoid definition. Of course a lib that dispatches to FL methods and derives Ord operators from Incidentally, shouldn't 1i actually be 1a or 1.1? |
@safareli , a counterexample please? |
Hi @gabejohnson, You are right, but the behaviour of values that does not belong to the same Ord is not specified, just recommended. |
@xgbuils actually you are right i misinterpreted you example. |
@xgbuils has a really good point. Additionally, the implementations of This should only be expensive in a situation where you have a deeply nested structure. |
Would you like to discuss this further, Gabe, or are you now happy with the status quo? |
I think it can be closed. |
Almost immediately after 3.2 was cut I thought about how libraries (Sanctuary in particular) would implement it. I realized that either there were going to be extra equality checks (not performant) or an indirect definition in terms of
gt
(unnecessarily convoluted).An alternative would be to define Ord in terms of
lt
andequals
.laws:
a.lt(b)
thenb.lt(a) === false
(irreflexivity)a.lt(b)
orb.lt(a)
ora.equals(b)
(trichotomy)a.lt(b)
andb.lt(c)
, thena.lt(c)
(transitivity)An added bonus is that we could refer to
lt
asprecedes
which has no connotation of quantity.The text was updated successfully, but these errors were encountered: