Haskell中的联合函数

时间:2013-10-08 02:28:11

标签: haskell union

我一直在Haskell中编写代码,但无法理解实现union函数的想法。 我还发现了一些嵌入在Haskell平台中的函数定义。但问题是我需要一种简洁易懂的方法来使其发挥作用。 任何人都可以帮助我吗?

2 个答案:

答案 0 :(得分:8)

假设您正在讨论union :: Eq a => [a] -> [a] -> [a],它接受​​两个输入列表并返回包含每个参数列表的所有元素的第三个列表,那么它在Data.List中定义,它位于{{ 1}}包。

在源代码中,它分为两个函数,广义函数base,它采用等式的自定义定义(类型的函数等于unionBy),然后定义使用{(==) :: a -> a -> Bool的函数。 1}}类型类通过传入Eq作为平等的具体实现。

(==)

我们可以将union :: (Eq a) => [a] -> [a] -> [a] union = unionBy (==) 替换为(==)代码,因为Haskell允许我们使用等式推理。

unionBy

同样的模式在union = unionBy (==) -- so... union :: Eq a => [a] -> [a] -> [a] union xs ys = xs ++ foldl (flip (deleteBy (==))) (nubBy (==) ys) xs unionBydeleteBy的定义中再出现两次,两者都遵循相同的约定。 nubBy从列表中删除元素,delete返回唯一元素列表。我们将再次简化定义以消除nub的所有痕迹,并简单地假设元素(==)已定义a

Eq

现在这个定义可能更具可读性。 union xs ys = xs ++ foldl (flip delete) (nub ys) xs union的{​​{1}} xs附加到ys的唯一(“xs床”)值已被处理nubys的最终结果是逐个尝试foldl (flip delete) _ xs来自foldl delete的每个元素xs。结果意味着(nub ys) union xs ys附加到xs的每个唯一元素,而不是ys中的xs


顺便说一句,有了这个来源,我们可以注意到union的一些古怪行为,例如它如何处理第一个参数中的重复项与第二个参数不同

union [1,1,2] [2] == [1,1,2]
union [2] [1,1,2] == [2,1]

这有点令人失望,这是使用[]来表示Set的结果 - 就像union的概念一样。但是,如果我们使用Set.fromList查看结果,那么我们就可以了。

xs, ys :: Eq a => [a]
Set.fromList (xs `union` ys) == Set.fromList xs `Set.union` Set.fromList ys

这也为我们提供了union

的另一个定义
union xs ys = Set.toList (Set.fromList xs `Set.union` Set.fromList ys)

那么foldl怎么办呢?让我们解开foldl的定义来看,再次滥用等式推理。

union xs ys = xs ++ (case xs of
  []      -> nub ys
  (x:xs') -> foldl (flip delete) (delete x (nub ys)) xs'
  )

这应该让诀窍更加明显 - 它会绕过xs的元素,从(nub ys)逐个删除它们。


虽然希望这有助于使union中的代码更加清晰,但真正的主要原因应该是等式推理是解析Haskell代码的强大工具。不要害怕直接通过手动内联函数的定义来简化代码。

答案 1 :(得分:0)

我不确定这个union是否符合您的要求但是相当简单。 我需要自己的功能来删除重复项。

rmdups ls = [d|(z,d)<- zip [0..] ls,notElem d $ take z ls]

它与同一目的的任何递归函数相同。

union l1 l2 = let l = l1 ++ l2 in rmdups l