Skip to content
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

Checking Empty child of Internal nodes #59

Open
kgeorgiy opened this issue May 31, 2013 · 3 comments
Open

Checking Empty child of Internal nodes #59

kgeorgiy opened this issue May 31, 2013 · 3 comments

Comments

@kgeorgiy
Copy link
Contributor

Documentation states that Empty allowed only as a root of the tree. Both performance and functions (e. g. binarySetOpWithKey) depends on this invariant. But, now it is not checked by tests at all.

Unfortunately, there is no way to write such check function using public API only.

AFAIU there are two ways to solve this problem:

  1. Make one of the API functions (e.g. toList) to check this. This check will cost just a one call on the root tree.
  2. Provide special check function in the API.

I think first variant is better.

@isturdy
Copy link
Contributor

isturdy commented May 31, 2013

I believe that binarySetOpWithKey will throw an error if it encounters Empty anywhere but at the top level; one can thus use it to check (as Criterion handles exceptions as failed tests). I, at least, would prefer a dedicated validation function to adding size/complexity to an API function (even if it does not hurt speed, it would cause code bloat in all callers, and could conceivably bump the function over GHC's inlining threshold).

@kgeorgiy
Copy link
Contributor Author

You are right! difference m m should throw error if an unexpected Empty is encountered.

I'am not aware about specific features of GHC inlining, but AFAIU toList.go cannot be inlined due to recursive (not tail-recursive, specifically) nature. In this case, the following implementation should me a bit more efficient due to inlainability of the top.

toList :: CritBit k v -> [(k, v)]
toList (CritBit root) = top root
  where
    top Empty = []
    top node = go node []

    go (Internal l r _ _) next = go l (go r next)
    go (Leaf k v) next         = (k,v) : next
    go Empty next              = error "CritBit: Empty child of Internal node"

@kgeorgiy
Copy link
Contributor Author

Pardon, for better performance the List.top should be defined as

    top Empty = []
    top (Internal l r _ _) next = go l (go r next)
    top (Leaf k v) next         = (k,v) : next

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants