haskell-unordered-containers / unordered-containers

Efficient hashing-based container types
BSD 3-Clause "New" or "Revised" License
222 stars 97 forks source link

Expanded unionWith for different value types #488

Open Benjamin-McRae-Tracsis opened 4 months ago

Benjamin-McRae-Tracsis commented 4 months ago

Hi, I think there's space for a unionWith with a signature like unionWith' :: Hashable k => (a -> c) -> (b -> c) -> (a -> b -> c) -> HM.HashMap k a -> HM.HashMap k b -> HM.HashMap k c.

This differs from the existing unionWith by allowing different ways to transforming the input maps, and being more specific in how to combine maps with differing value types.

My current usage is generally HM.unionWith' This That These. This would be a more powerful function.

phadej commented 1 month ago

That's what alignWith from semialign package does. The (a -> c) -> (b -> c) -> (a -> b -> c) is a way to represent These a b -> c.

(EDIT: HM.unionWith' This That These is align).

So if you are already using these, I don't see a reason for you to not depend on semialign.

Benjamin-McRae-Tracsis commented 1 month ago

The case I was using was just one example which could use semialign's alignWith, but I feel like it would be a useful function to have without relying on other packages.

phadej commented 1 month ago

FWIW, https://hackage.haskell.org/package/containers-0.7/docs/Data-Map-Merge-Lazy.html#v:merge has in its docs

unionWithKey f = merge preserveMissing preserveMissing (zipWithMatched f)

The alignWith in semialign is defined as

    alignWith f = Map.merge (Map.mapMissing (\_ x ->  f (This x)))
                            (Map.mapMissing (\_ y ->  f (That y)))
                            (Map.zipWithMatched (\_ x y -> f (These x y)))

so the building blocks are there.

Benjamin-McRae-Tracsis commented 1 month ago

merge-style function would be nice to add to unordered-containers so we could do things like this, yes.