-
Notifications
You must be signed in to change notification settings - Fork 178
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
test that instances for Eq and Ord agree with going via toAscList #670
test that instances for Eq and Ord agree with going via toAscList #670
Conversation
prop_instanceEqIntSet x y = (x == y) == (toAscList x == toAscList y) | ||
|
||
prop_instanceOrdIntSet :: IntSet -> IntSet -> Bool | ||
prop_instanceOrdIntSet x y = (compare x y) == (compare (toAscList x) (toAscList y)) |
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.
We already have prop_ord
for this. I don't see a similar prop_eq
though.
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.
not exactly "this" (prop_ord
uses toList
, I think it should use toAscList
#470 (comment) )
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.
Ah, yes, toAscList
is a bit more correct. That said, I would be astonished if we made toList
do something different. While it's true that it's not documented as producing keys in order, it's also not explicitly documented as potentially producing keys in some other order. There are almost certainly people whose code will break in horrible ways if we change that.
that avoids toAscList and walks the tree directly. See haskell#470
How worried should I be about travis failing? I am using |
It's better now - travis breaks only for ghc-7.8.4, which does not have |
Travis has to work, yeah. But you don't have to run the detailed test on 7.8. |
Can you try to give the helper functions somewhat more informative names, and explain what they do in comments? |
Sorry for 7.8.4 I have difficulty testing locally: for me it's either this:
or that:
|
Can't you test using |
relateTop t1@(Tip p1 bm1) t2@(Bin p2 m2 l2 r2) | ||
| mixed t2 = combine_right (relate t1 r2) | ||
| otherwise = relate t1 t2 | ||
relateTop t1@(Tip _ _) t2@(Tip _ _) = relateTipTip t1 t2 |
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 haven't tried to work through it, but mixed
strikes me as an odd way to organize this. Would this work better?
splitSign :: IntSet -> (IntSet,IntSet)
splitSign t@(Tip kx _)
| kx >= 0 = (Nil, t)
| otherwise = (t, Nil)
splitSign t@(Bin p m l r)
-- m < 0 is the usual way to find out if we have positives and negatives (see findMax)
| m < 0 = (r, l)
| p < 0 = (t, Nil)
| otherwise = (Nil, t)
splitSign Nil = (Nil, Nil)
that splits an IntSet
into the negative and non-negative elements. Then
compare xs ys
| (xsNeg, xsNonNeg) <- splitSign xs
, (ysNeg, ysNonNeg) <- splitSign ys
= case relate xsNeg ysNeg of
Less -> LT
Prefix -> if null xsNonNeg then LT else GT
Equals -> orderingOf (relate xsNonNeg ysNonNeg)
FlipPrefix -> if null ysNonNeg then GT else LT
Greater -> GT
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.
OK I can do this - but I was hoping that if relateTop
and orderingOf
get inlined, it'll result in the same code.
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.
Well, the thing I'm really going for amounts to structuring relateTop
more clearly. If you want to maintain the separation you describe, you can definitely do that with this structure as well. That would be totally fine by me.
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 am now (81bae9c) using the code that you proposed.
-- | precondition: each argument is non-Nil and non-mixed | ||
relate :: IntSet -> IntSet -> Relation | ||
relate t1@(Tip p1 bm1) t2@(Tip p2 bm2) = relateTipTip t1 t2 | ||
relate t1@(Bin p1 m1 l1 r1) t2@(Bin p2 m2 l2 r2) |
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.
Can't we play any tricks here? I have to think there's some way to use the prefixes and masks. For example, if we have
t1 = Bin 0100000 0000100 l1 r1
t2 = Bin 0010000 0001000 l2 r2
I think we can reach a conclusion immediately.
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.
In a bit more detail.... It seems to me that if p1 < p2
, then t1 ≤ t2
. Is that right? If so, then can we use the masks to determine (sometimes) that t1 < t2
?
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 hope that this happens automatically since the compiler should inline orderingOf $ relateTipTip ..
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, I mean pulling tricks in the Bin/Bin
case. You can surely do the same thing you do with Tip
: get lower and upper bounds for the trees, and if they don't overlap you have an answer.
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.
prefixes are tricky: assume wordSize is one (else multiply everthing by some large enough power of two), then fromList [2,3] has prefix 10 (binary) but fromList[3,4] has smaller prefix 0 (?)
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.
Okay, but can't you use your lower bound/upper bound calculation anyway? If the upper bound of one tree is less than the lower bound of the other, I think that's it.
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.
lower/upper-bound: yes this should be correct for any Tip/Bin combo:
| succUpperbound t1 <= lowerbound t2 = Less
| lowerbound t1 >= succUpperbound t2 = Greater
For now, this is inside the guards of some of the pattern matches but this could also be inverted (compare bounds first, and pattern match only if needed). This needs benchmarking (not today).
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 think that computing "lowerbound" inside a branch of a pattern match is better: the inliner then should be able to remove the pattern match that is in the implementation of "lowerbound" (does it really?)
I inserted the lower-upper test in the Bin/Bin case as helps to avoid recursion.
Bodigrim found new `Ord` instance in haskell#783. Put the old one one back.
Bodigrim found new `Ord` instance in haskell#783. Put the old one one back. Fixes haskell#783.
Bodigrim found a bug in the new `Ord` instance in haskell#783. Put the old one one back. Fixes haskell#783.
The implementation changes for |
add test case, see #470