【问题标题】:Deriving associative containers from map从地图派生关联容器
【发布时间】:2020-09-08 20:49:02
【问题描述】:

containers 包中的Data.Map.Lazy 模块中有Map 类型(关联数组):

data Map k a = ...

我可以从这种类型派生Set

import qualified Data.Map.Lazy as Map
newtype Set a = Set (Map.Map a ())

但同一包中的Data.Set 模块没有。是因为性能问题吗?

此外,我可以通过类似的方法推导出 C++ 的 std::multisetstd::multimap 等效项:

type Occur = Int
newtype MultiSet a = MultiSet (Map.Map a Occur)
newtype MultiMap k a = MultiMap (Map.Map k (MultiSet a))

因为containers 包没有提供这样的类型,我实际上是用我自己的实现来实现这些类型的。

优点是很容易为这些类型实现实用程序,例如 C++ 的 sizeinserterase 的(纯功能)等效项。例如:

instance Foldable MultiSet where
    foldMap f (MultiSet xs) = Map.foldMapWithKey (\x o -> stimes o (f x)) xs
    toList = toAscList
    null (MultiSet xs) = null xs
    length = size

size :: MultiSet a -> Occur
size (MultiSet xs) = sum xs

insert :: Ord a => a -> MultiSet a -> MultiSet a
insert x = insertMany x 1

insertMany :: Ord a => a -> Occur -> MultiSet a -> MultiSet a
insertMany x n (MultiSet xs) = MultiSet (Map.alter (\maybeo -> case maybeo of
    Nothing -> Just n
    Just m -> maybeClampNeg (m + n)
    ) x xs)

clampNeg :: Occur -> Occur
clampNeg n = if n < 0 then 0 else n

maybeClampNeg :: Occur -> Maybe Occur
maybeClampNeg n = case clampNeg n of
    0 -> Nothing
    n' -> Just n'

delete :: Ord a => a -> MultiSet a -> MultiSet a
delete x = deleteMany x 1

deleteMany :: Ord a => a -> Occur -> MultiSet a -> MultiSet a
deleteMany x n (MultiSet xs) = MultiSet (Map.update (maybeClampNeg . subtract n) x xs)

这些实现会不会出现性能问题?

【问题讨论】:

    标签: dictionary haskell set multimap multiset


    【解决方案1】:

    Set 类型未实现为 Map k (),因为在该实现中,每个条目还携带一个值 (),这是纯粹的开销。

    您的多集实现与one in Hackage 基本相同。

    This Multimap,另一方面,实现为列表映射。这并不意味着您的提议有任何问题;事实上,对于某些用例,它可能会更好。

    然而,这确实说明了一个更广泛的设计问题; Haskell 中这种数据结构的可组合性意味着在实践中创建这种结构比尝试创建包含嵌套容器的所有可能组合的库更容易。

    【讨论】:

      猜你喜欢
      • 2018-10-12
      • 1970-01-01
      • 1970-01-01
      • 2011-01-17
      • 1970-01-01
      • 1970-01-01
      • 2020-12-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多