Skip to content

Data.Set: add insertUnlessMember #161

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

Closed
andreasabel opened this issue Jul 21, 2015 · 11 comments
Closed

Data.Set: add insertUnlessMember #161

andreasabel opened this issue Jul 21, 2015 · 11 comments

Comments

@andreasabel
Copy link
Member

For Data.Set, I am missing something comparable to Map.lookupInsertWithKey that combines a lookup and an insert. Suggestion (specification):

insertUnlessMember :: Ord a => a -> Set a -> Maybe (Set a)
insertUnlessMember a s = if member a s then Nothing else Just $ insert a s

Of course, that should have an efficient implementation that only traverses the tree once.

@tibbe
Copy link
Member

tibbe commented Jul 21, 2015

Might be worth checking the performance gain. Lookups are usually much faster than inserts so a lookup + insert is often as fast as just an insert.

@andreasabel
Copy link
Member Author

Yes, maybe, but why then has Map such a function and not Set?

@tibbe
Copy link
Member

tibbe commented Jul 22, 2015

Someone probably thought it was faster (perhaps it is!), but I doubt it was tested.

@tibbe
Copy link
Member

tibbe commented Jul 22, 2015

We could add it for consistency, but I would at least like to know if it actually helps. Our API suffers from a combinatoric explosion unfortunately, so I'd like to avoid growing it if not necessary.

@treeowl
Copy link
Contributor

treeowl commented Jul 22, 2015

When comparison is expensive, the combined approach obviously wins. Obviously, that's not the best scenario for Set anyway, but it might be worth considering.

@tibbe
Copy link
Member

tibbe commented Jul 22, 2015

@treeowl right, it can in theory be arbitrarily expensive. In the typical case however the runtime is dominated by the allocation done on insert. It's a typical memory bound problem (like most performance problems on modern CPUs).

@foxik
Copy link
Contributor

foxik commented Jul 22, 2015

Personally I am not sure we can make the implementation faster than the suggested one, notably when comparison is cheap like in the Set Int case. The reason are the Maybe allocations on every level.

Together with the fact that the proposed function is a simple combination of existing functions and is at most twice slower (assuming lookup complexity is dominated by insert complexity), I am not a big fan.

But please do not hesitate to surprise me with benchmark results :-)

@m-renaud
Copy link
Contributor

This is very similar to #291, #166, #290 which propose:

lookupEntry :: (Ord a) => a -> Set a -> Maybe a
lookupEntry :: (Ord k) => k -> Map k v -> Maybe (k, v)

Would these functions address your use case? These have already (mostly*) been approved by the libraries committee and have the potential of going into the API soon.

* There was general agreement, but the discussion was a while ago so I'm going to raise it again to make sure everyone is on board still.

@treeowl
Copy link
Contributor

treeowl commented Dec 26, 2017 via email

@m-renaud
Copy link
Contributor

Oh yeah, duh, I read this wrong. Sorry for the noise.

@sjakobi
Copy link
Member

sjakobi commented Jul 15, 2020

With the Data.Set.alterF function added in 0.6.3.1, it's easy to define

insertUnlessMember = alterF (\member_ -> if member_ then Nothing else Just True)

I'll tentatively close this issue, but feel free to reopen, if there's more to do here.

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

No branches or pull requests

6 participants