Haskell 创建集合数据类型

Haskell 创建集合数据类型,haskell,types,Haskell,Types,所以我需要在Haskell中创建一个集合数据类型 所以,在我问题的第一部分,我需要定义 type Set a = ... 我把它设置为 type Set a = Set [a] 因为集合就是一个字母列表,对吗? 或者,正确的方法是什么 type Set a = ([a]) 然后,对于下一部分,我需要实现一个函数 setSuchThat :: (a -> Bool) -> (Set a) 该函数采用特征函数f并返回一个集合,使得值x(适当类型)仅在f(x)为真时才在集合中。因此

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

所以,在我问题的第一部分,我需要定义

type Set a = ...
我把它设置为

type Set a = Set [a]
因为集合就是一个字母列表,对吗? 或者,正确的方法是什么

type Set a = ([a])
然后,对于下一部分,我需要实现一个函数

setSuchThat :: (a -> Bool) -> (Set a)
该函数采用特征函数f并返回一个集合,使得值x(适当类型)仅在f(x)为真时才在集合中。因此,一个正在使用的例子是

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

所以我现在的问题是,在这个函数中,我需要计算这个函数,得到“coke”,然后把它添加到我的集合中。我想我只是不明白,在这个函数中,我该怎么做。

按照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
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
所以空集就是
setSuchThat(const False)
——对于任何给定的元素,它总是用“否”回答“集合是否包含此元素?”

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

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

> setSuchThat (== "coke") `contains` "pepsi"
False
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
作为练习,尝试实现其他设置函数,如
delete
intersect
difference

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

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

基于已布置的内容:

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


您所做的一切就是获取函数
f
并将其应用于变量
x
设置的整个点,即
要通过
f
x
并仅返回
f x

查找
过滤器的源代码。您将发现
setSuchThat=filter
。这是不可能的。有无限多个可能的字符串。程序如何知道它何时具有将返回
True
的所有值?一个更现实的解决方案是使用
过滤器
。如果您必须实现的唯一功能是
setSuchThat
,那么让我建议
键入Set A=A->Bool
。然后你会发现
setSuchThat
微不足道。是的,我还不完全确定该做什么,但是是的,还有更多的函数需要实现,比如并集和交集。它可以是
type Set a=[a]
data Set a=Set[a]
。如果希望
Set
成为一个独特的数据结构,而不仅仅是一个列表的另一个名称,则必须使用后者。您可能希望这样,因为您实际上不希望
Set[1]++Set[1]
成为
Set[1,1]
,甚至不希望编译。