I would like to union two Map instances with a monadic function. This becomes a problem because of the unionWith
type signature:
unionWith :: Ord k => (a -> a -> a) -> Map k a -> Map k a -> Map k a
I'm looking for a smart way to do this. Here is my naive implementation:
monadicUnionWith :: (Monad m, Ord k) => (a -> a -> m a) -> Map k a -> Map k a -> m (Map k a)
monadicUnionWith f mapA mapB = do
let overlapping = toList $ intersectionWith (\a b -> (a,b)) mapA mapB
mergedOverlapping <- liftM fromList $ mapM helper overlapping
return $ union (union mergedOverlapping mapA) mapB
where
helper (k, (a,b)) = do
c <- f a b
return (k, c)
Note that union
is left biased
Not sure if it is more efficient, but it is somewhat cooler (as it involves storing monadic values in the map):
monadicUnionWith :: (Monad m, Ord k) => (a -> a -> m a) -> Map k a -> Map k a -> m (Map k a)
monadicUnionWith f mapA mapB =
Data.Traversable.sequence $ unionWith (\a b -> do {x <- a; y <- b; f x y}) (map return mapA) (map return mapB)
And if you want you can use
(\a b -> join (liftM2 f a b))
as the parameter to unionWith
, or even
((join.).(liftM2 f))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With