使用子集语言Core Haskell创建函数以删除列表中的重复项

时间:2013-07-03 16:32:45

标签: haskell recursion duplicate-removal

我正在使用的语言是Haskell的一个子集,名为Core Haskell,它不允许使用Haskell的内置函数。例如,如果我要创建一个函数来计算项x出现在列表xs中的次数,那么我会写:

count = \x -> 
            \xs -> if null xs 
                     then 0
                     else if x == head xs 
                            then 1 + count x(tail xs) 
                            else count x(tail xs)

我正在尝试创建一个输出列表xs并删除其重复值的函数。例如。 remdups(7:7:7:4:5:7:4:4:[])=> (7:4:5:[])

任何人都可以提供任何建议吗?

谢谢!

2 个答案:

答案 0 :(得分:2)

我猜你是学生,这是一个家庭作业问题,所以我会给你一部分答案并让你完成它。为了编写remdups,有一个函数可以告诉我们列表是否包含元素。我们可以使用递归来做到这一点。使用递归时,首先要问自己“基本情况”是什么,或者最简单的情况。好吧,当列表为空时,显然答案是False(无论字符是什么)。那么现在,如果列表不为空怎么办?我们可以检查列表中的第一个字符是否匹配。如果是,那么我们知道答案是True。否则,我们需要检查列表的其余部分 - 我们通过再次调用该函数来完成。

elem _ []       = False
elem x (y:ys)   = if x==y
                    then True
                    else elem x ys

下划线(_)只是意味着“我不打算使用这个变量,所以我甚至都懒得给它命名。”这可以写得更简洁:

elem _ []       = False
elem x (y:ys)   = x==y || elem x ys

remdups有点棘手,但我怀疑你的老师给了你一些提示。接近它的一种方法是想象我们处理列表的过程中途。我们有一部分尚未处理的列表,以及已处理的列表的一部分(并且不包含任何重复项)。假设我们有一个名为remdupHelper的函数,它接受这两个参数,称为remainingfinished。它将查看remaining中的第一个字符,并根据该字符是否在finished中返回不同的结果。 (该结果可以递归调用remdupHelper)。你能写remdupHelper吗?

remdupHelper = ???

获得remdupHelper后,您就可以编写remdups了。它只是在初始条件下调用remdupHelper,其中尚未处理任何列表:

remdups l = remdupHelper l []             -- '

答案 1 :(得分:1)

这适用于Ints:

removeDuplicates :: [Int] -> [Int]
removeDuplicates = foldr insertIfNotMember []
           where
            insertIfNotMember item list = if (notMember item list)
                          then item : list
                          else list

notMember :: Int -> [Int] -> Bool
notMember item [] = True
notMember item (x:xs)
          | item == x = False 
          | otherwise = notMember item xs

它的工作原理应该是显而易见的。唯一“棘手”的部分是折叠器的类型是:

(a -> b -> b) -> b -> [a] -> b

但在这种情况下,b与[a]结合,因此它变为:

(a -> [a] -> [a]) -> [a] -> [a] -> [a]

因此,您可以传递insertIfNotMember函数,该函数的类型为:

Int -> [Int] -> [Int]   -- a unifies with Int