haskell / containers

Assorted concrete container types
https://hackage.haskell.org/package/containers
315 stars 178 forks source link

Consider adding applicative/monadic versions of adjust/update/alter functions #278

Open sergv opened 8 years ago

sergv commented 8 years ago

These three functions are pure, which is really great. But I believe purity gets it the way in the following use case: add key-value pair if key is not present or throw error in a monad if key is already present.

Sharing traversal for both presence check and update will avoid redundant work.

treeowl commented 8 years ago

I've added alterF to Data.Map (with a seriously over-engineered implementation). I copied the at code from Control.Lens.At to offer the same in Data.IntMap, where it's really not worth trying to be clever except possibly to add a rewrite rule for Identity. I'm open to offering adjustA as well, which could reuse code from alterF for Data.Map and steal ix code from Control.Lens.At for Data.IntMap and Data.Sequence. You should send a proposal to the libraries list. I'm not convinced updateA would get much use, but you're welcome to bring it up on the list if you like.

treeowl commented 8 years ago

I just realized we can include Data.Set and Data.IntSet in this game if we want. lens takes them to Maybe (), which is good for lens consistency, but we'd want to use Bool instead.

sergv commented 8 years ago

Thanks for alterF, that's exactly what I needed :+1:

mitchellwrosen commented 7 years ago

Neat, I think alterF subsumes some work I've done over the past day or so on integrating focus with containers: https://github.com/mitchellwrosen/containers-focus

The main motivator was deleting an element and looking it up at the same time:

deleteLookup :: Ord k => k -> Map k a -> (Maybe a, Map k a)
deleteLookup = focus (, Remove)

alterF can do it too with the (x ,) functor:

deleteLookup :: Ord k => k -> Map k a -> (Maybe a, Map k a)
deleteLookup = alterF (, Nothing)

However, I wouldn't exactly say this is obvious, especially to a newer Haskeller. Perhaps the documentation could be improved around this function.

treeowl commented 7 years ago

I'm always open to documentation suggestions and pull requests, and I think it does make sense to add an explanation of how to use alterF with the rather important (,) x functor. That said, I don't want to copy a lens tutorial into containers. I'd much rather link to lens documentation somewhere else, either to lens specifically, to some less ambitious library, or perhaps to a general tutorial. Do you have suggestions for link targets?

mitchellwrosen commented 7 years ago

I don't think a lens tutorial is necessary, as alterF isn't quite compatible out-of-the-box with lenses anyway. How about just a bunch of example uses for the function that can't be implemented any other way?

Identity and Const are bad examples - these just give you alter and lookup.

Deleting a value and looking it up at the same time:

deleteLookup :: Ord k => k -> Map k a -> (Maybe a, Map k a)
deleteLookup = alterF (, Nothing)

Deleting a value and returning whether or not it was deleted:

deleteSuccess :: Ord k => k -> Map k a -> (Bool, Map k a)
deleteSuccess = alterF (\x -> (isJust x, Nothing))

Inserting a value and return what was overwritten:

overwrite :: Ord k => k -> a -> Map k a -> (Maybe a, Map k a)
overwrite k a = alterF (, Just a)

... yeah these are all the (,) functor. Can't think of any other examples =P