Haskell列表删除重复项不能完全正常工作

时间:2018-04-19 16:37:31

标签: haskell

我为删除列表中的常用元素创建了此代码,但它仅适用于整数列表我有一个示例

remove [ A "List", A "List", A "Gone", A "Still"]

它必须作为输出[ A "List", A "Gone", A "Still"] 它不起作用给出一个未定义的构造函数A

remove [] = []
remove (x:xs) | x `elem` xs = remove xs
              | otherwise = x : remove xs

1 个答案:

答案 0 :(得分:3)

这里的问题本身不是函数本身,而是输入列表:

remove [ A "List", A "List", A "Gone", A "Still"]

它包含一个元素列表,每个元素都有数据构造函数 A后跟一个字符串。在像Prolog这样的语言中,可以动态引入仿函数,但不能在Haskell中引入:Haskell是静态类型的,因此您需要声明类型。例如,我们可以声明类型:

data A = A String deriving (Eq, Show)

现在我们声明了一个类型A,其中有一个数据构造函数A,它将String作为参数。我们使它成为deriving (Eq, Show),这样两个A是相等的,因为它们具有相同的数据构造函数(但由于只有一个,所以总是如此),以及参数应该是相同的。 Show使我们能够打印A个实例。

所以现在它至少会产生输出(不会产生编译器错误)。但是函数本身仍然存在一个潜在的问题:在这里检查列表中 tail 的成员资格。可能有两个问题:

  1. 我们将始终保留 last ,因此remove [1, 4, 1, 2]将返回[4, 1, 2],而我们可能希望返回[1, 4, 2];和
  2. 如果我们处理无限列表,那么对于非重复元素elem,将继续寻找重复。结果最终Haskell将耗尽内存并崩溃。
  3. 我们最好在这里使用一个存储迄今为止观察到的元素的累加器,并在该列表上调用elem,如:

    remove :: Eq a => [a] -> [a]
    remove = go []
        where go _ [] = []
              go seen (x:xs) | elem x seen = go seen xs
                             | otherwise = x : go (x:seen) xs