5

我想将两个Map实例与一个单子函数联合起来。由于unionWith类型签名,这成为一个问题:

unionWith :: Ord k => (a -> a -> a) -> Map k a -> Map k a -> Map k a

我正在寻找一种聪明的方法来做到这一点。这是我天真的实现:

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)

注意union是左偏

4

1 回答 1

6

不确定它是否更有效,但它更酷(因为它涉及在映射中存储单值):

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)

如果你愿意,你可以使用

(\a b -> join (liftM2 f a b))

作为 的参数unionWith,甚至

((join.).(liftM2 f))
于 2013-11-10T22:55:16.067 回答