Haskell - 列表的连接

时间:2014-04-22 13:13:29

标签: haskell

我尝试连接两个列表,使得结果列表中的元素只出现一次。 我不想使用预定义的功能,因为那样太容易了。因为我正在学习haskell,我写下面的代码:

import Data.List

add :: [Int] -> [Int] -> [Int]

add xs ys = zs ++ ws
        where
        zs = if elem x (x:xs) == True then x:(elem x xs)
             else elem x xs
        ws = if elem y (y:ys) == True then y:(elem y ys)
             else elem y ys

我只使用预定义的函数elem,它告诉我元素是否出现在列表中。 我的想法是首先列出一个列表并使用" elem"找出列表xs的第一个元素x是否多次存在于列表中。如果是这样,那么我接受x并使用":#34; -operator和(elem x xs)我建立一个新列表,直到检查完所有元素。 我对第二个列表做了同样的事情。 如果完成,那么我使用" ++" - 运算符用zs ++ ws连接无副本列表。所以当我编译它时,ghci告诉我x和y不在范围内。我的错误在哪里?

2 个答案:

答案 0 :(得分:7)

您还没有给出此功能的预期输入/输出示例,因此我将使用您提供的定义 -

  

"连接两个列表,使得结果列表中的元素只出现一次。"

似乎有一种直截了当的方法 -

  1. 连接两个列表。
  2. 删除重复项。
  3. 因此,让我们假设您有一个函数unique :: [Int] -> [Int],可以从列表中删除重复项(同时保持元素的顺序)。那么你想要的就像

    一样简单
    add :: [Int] -> [Int] -> [Int]
    add xs ys = unique (xs ++ ys)
    

    因此,您已将问题简化为编写unique函数的简单问题。你能做到吗?

答案 1 :(得分:4)

我认为克里斯的解决方案是可行的方法。但是为了教学,我将讨论你的方法中的一些问题。首先,为了在函数x中引用yadd,必须在某处定义它们。我怀疑你的意图是什么:

add (x:xs) (y:ys) = ...

现在,您可以在函数定义中使用xxsyys。现在任何时候你都想写下这样的东西:

if condition == True then...

知道写

更简单,更清晰
if condition then...

所以我认为你打算写一些这样的东西:

add (x:xs) (y:ys) = zs ++ ws
    where
        zs = if elem x xs then xs
                          else x:xs
        ws = if elem y ys then ys
                          else y:ys

除了您还想进行某种递归以确保xsys中的所有元素都不重复。然而,递归两个列表将是非常尴尬和困难的。这就是为什么克里斯的答案更好,以及更接近Haskell-y方式的原因。

另请注意,而不是

elem x xs

写起来可以更具可读性

x `elem` xs