haskell / containers

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

Function for updating with default value (mostly for nested maps) #888

Open Lev135 opened 1 year ago

Lev135 commented 1 year ago

Maybe, I'm doing something wrong, but this combination is very frequent in my programms. Imagine we have some nested map

m :: Map Foo (Map Bar Baz)

and we want to insert a value baz to the bar of foo. I think it would be nice to have something like

mupdate :: Monoid a => (a -> a) -> k -> Map k a -> Map k a
mupdate upd = alter (Just . upd . fromMaybe mempty)

to call this like mupdate (insert bar baz) foo. Maybe with upsert from #809 it will be also acceptable --- just upsert (insert bar baz . fromMaybe mempty) foo or even there is a perfect way using currently implemented functionality, but I can't see them.

P. S. of course, this can be easily done throw non from lens, but lens are not always advisable

alexfmpe commented 1 year ago

Maybe you want insertWith union foo (singleton bar baz)?

> f a b c = insertWith union a (singleton b c)

> :t f
f :: (Ord k1, Ord k2) => k1 -> k2 -> a -> Map k1 (Map k2 a) -> Map k1 (Map k2 a)

> f "0" "1" "2" mempty
fromList [("0",fromList [("1","2")])]

> f "0" "1" "2" $ singleton "0" mempty
fromList [("0",fromList [("1","2")])]

> f "0" "1" "2" $ singleton "0" $ singleton "1" ""
fromList [("0",fromList [("1","2")])]

Alternatively, see https://hackage.haskell.org/package/monoidal-containers. That should let you do nested inserts direcly


let path = singleton a $ singleton b $ singleton c $ First d
in path <> oldMap