所以我需要在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中。我想我只是不明白,在这个函数中,我会怎么做。
答案 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
作为练习,请尝试实施其他设置功能,例如delete
,intersect
和difference
。
这种方法的一个缺点是每个查找都是线性-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
并将其应用于变量x
。 setSuchThat
的全部内容将通过f
和x
,并仅返回f x
。