这不起作用
data Cutlery = Knife | Fork deriving (Show,Eq)
let x = [Knife,Fork]
let set1 = Set.fromList x
定义时
data Cutlery = Knife | Fork deriving (Show,Ord,Eq)
解决了这个问题,但没有意义。 Data.Set是否与集合的数学定义不同?
答案 0 :(得分:19)
A Data.Set
捕获集合的数学抽象,但它不相同。主要区别在于Data.Set
要求对其元素进行排序,而数学集只要求其元素具有可比性。
要求Ord
的原因是效率。通过定义
data Set a = Set [a]
即。在引擎盖下它只是一个列表,我们确保我们永远不会插入重复的元素。 elem
和insert
操作将是
elem a (Set as) = any (a ==) as
insert a (Set as) | a `elem` as = Set as
| otherwise = Set (a:as)
但是,这意味着elem
和insert
都是O( n )操作。如果我们想要做的比这更好,标准方法是
Ord
实例)Hashable
实例)。 Data.Set
的作者选择的实现是使用二叉树,您可以通过转到source看到。实施或多或少
data Set a = Bin a (Set a) (Set a)
| Tip
现在您可以将elem
函数编写为
elem :: Ord a => a -> Set a -> Bool
elem = go
where
go _ Tip = False
go x (Bin y l r) = case compare x y of
LT -> go x l
GT -> go x r
EQ -> True
这是一个O(log n )操作,而不是O( n )。插入比较棘手(因为你需要保持树平衡)但类似。
在哈希集中,在插入和删除元素时不直接比较元素。相反,每个元素散列为整数,并存储在基于该整数的位置。
理论上,这不需要Ord
实例。在实践中,您需要一些方法来跟踪散列到相同值的多个元素,Data.HashSet
的开发人员选择的方法是将多个元素存储在常规Data.Set
中,因此它会变为毕竟你做需要Ord
实例!
data HashSet a = HashSet (Data.IntMap.IntMap (Data.Set.Set a))
它本可以写成
data HashSet a = HashSet (Data.IntMap.IntMap [a])
相反,如果有许多元素必须具有相同的值,那么会以某些低效率为代价来删除Ord
要求。
答案 1 :(得分:7)
Data.Set
是否与集合的数学定义不同?
显然,数学集可以是无数无限的 - 你无法用计算机,甚至图灵机来表示这一点。
但你要找的答案是这样的:Data.Set
是一种基于二叉树的数据类型,需要对元素进行总线性排序才能知道是否放置并稍后在左侧或右侧找到某些内容节点的子树。因此,虽然可以实现没有Ord
约束的set数据类型,但这种特殊的,更有效的实现不会。
答案 2 :(得分:1)
Data.HashSet如果你想要一个无序集:
https://hackage.haskell.org/package/unordered-containers-0.1.4.6/docs/Data-HashSet.html
答案 3 :(得分:0)