创建Set数据类型

时间:2017-12-03 01:25:38

标签: haskell types

所以我需要在Haskell中创建一个Set数据类型。

因此,对于我的问题的第一部分,我需要定义

type Set a = ...

我把它设为

type Set a = Set [a]

因为Set只是一个alpha列表,对吧? 或者,正确的方法是

type Set a = ([a])

然后,对于下一部分,我需要实现一个函数

setSuchThat :: (a -> Bool) -> (Set a)

该函数采用特征函数f并返回一个集合,使得仅当f(x)为True时,值x(适当类型)才在集合中。所以它的一个例子就是,

setSuchThat (\x -> x == "coke")

所以现在我的问题是,在该函数中,我基本上需要评估该函数以获得“可乐”,然后将其添加到我的Set中。我想我只是不明白,在这个函数中,我会怎么做。

2 个答案:

答案 0 :(得分:4)

根据Daniel Wagner的建议,您可以将一个集合定义为谓词,指示元素是否在集合中:

type Set a = a -> Bool

为了更好的衡量,我会使用newtype使我们在使用集合时更清楚:

newtype Set a = Set { contains :: a -> Bool }

然后setSuchThat只在Set中包含一个谓词:

setSuchThat :: (a -> Bool) -> Set a
setSuchThat = Set

您可以使用contains函数测试集合中的成员资格:

> setSuchThat (== "coke") `contains` "coke"
True

> setSuchThat (== "coke") `contains` "pepsi"
False

所以空集只是setSuchThat (const False) - 对于任何给定的元素,它总是回答问题“集合是否包含这个元素?”和“否”。

然后,您可以通过使用新函数编写现有insert函数来实现contains等功能,以扩展具有新元素的集合:

insert :: (Eq a) => a -> Set a -> Set a
insert x s = Set $ \ x' -> x == x' || s `contains` x'

> insert "pepsi" (setSuchThat (== "coke")) `contains` "pepsi"
True

union等其他功能很简单:

union :: Set a -> Set a -> Set a
union s1 s2 = Set $ \ x -> s1 `contains` x || s2 `contains` x

> let sodas = setSuchThat (== "coke") `union` setSuchThat (== "pepsi")

> sodas `contains` "coke"
True

> sodas `contains` "pepsi"
True

> sodas `contains` "water"
False

作为练习,请尝试实施其他设置功能,例如deleteintersectdifference

这种方法的一个缺点是每个查找都是线性-O(n) - 在已插入或删除的元素数量中。此外,您不能简单地枚举集合的所有元素以将其转换为列表 - 您只能枚举 test 是否每个元素都是元素。但是,一个优点就是让你轻松代表无限集;例如,setSuchThat (> 0)包含所有非负数。

这就是为什么标准Data.Set类型使用基于树的数据结构而不是函数,将元素表示为实际值。使用该方法,可以在不增加集合大小的情况下删除值,并且由于它使用Ord而不是Eq,因此可以实现更有效的对数-O(log n) - 查找和插入。< / p>

答案 1 :(得分:1)

建立Jon Purdy所列出的内容:

您需要将Set a = a -> Bool视为您必须使用的限制。当您查看setSuchThat :: (a -> Bool) -> (Set a)时,您可以将其视为与setSuchThat :: (Set a) -> (Set a)setSuchThat :: (a -> Bool) -> (a -> Bool)相同。 setSuchThat有点像mcguffin,它只是让函数更清晰 - 这是不必要的。

您正在做的所有事情都是使用函数f并将其应用于变量xsetSuchThat的全部内容将通过fx,并仅返回f x