Haskell中的并函数

cygmwpex  于 2022-11-14  发布在  其他
关注(0)|答案(3)|浏览(239)

我一直在用Haskell编写代码,但无法理解实现联合函数的想法。我也发现了一些嵌入在Haskell平台中的函数定义。但问题是我需要一个简洁易懂的方法来使其工作。有人能帮助我吗?

vh0rcniy

vh0rcniy1#

假设你在讨论union :: Eq a => [a] -> [a] -> [a],它接受两个输入列表,并返回第三个列表,其中包含每个参数列表的所有元素,那么它在base包中的Data.List中定义。
在源代码中,它被分为两个函数,广义函数unionBy接受等式的自定义定义定义(类型等于(==) :: a -> a -> Bool的函数),然后通过传入(==)作为等式的具体实现来定义使用Eq类型类的函数。

union                   :: (Eq a) => [a] -> [a] -> [a]
union                   = unionBy (==)

不过,我们可以把(==)替换成unionBy代码,就像 haskell 让我们使用等式推理一样。

union = unionBy (==)

-- so...

union       :: Eq a => [a] -> [a] -> [a]
union xs ys =  xs ++ foldl (flip (deleteBy (==))) (nubBy (==) ys) xs

deleteBynubBy中的unionBy的定义中,同样的模式又出现了两次,这两个函数都遵循相同的约定。delete从列表中删除一个元素,而nub返回一个唯一元素的列表。我们'我将再次简化定义以消除(==)的所有痕迹,并简单地假设元素a具有定义的Eq

union xs ys = xs ++ foldl (flip delete) (nub ys) xs

xsysunionxs附加到唯一的(“nub床”)已由foldl (flip delete) _ xs处理的ys的值。得出foldl的最终结果是要逐一尝试将delete中的每个元素xs(nub ys)中取出。这意味着,union xs ysxs,它附加到ys中的每个唯一元素上,减去xs中的元素。
顺便说一句,通过这个源代码,我们可以注意到union的一些古怪行为,比如它如何将第一个参数中的重复项与第二个参数中的重复项区别对待

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

这有点令人失望,因为使用[]来表示类似Setunion概念的结果。

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代码的强大工具。不要害怕通过手动内联函数的定义来直接简化代码。

ijnw1ujt

ijnw1ujt2#

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

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

它的作用与任何具有相同目的的递归函数相同。

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

yrdbyhpb3#

我可能误解了这个问题,但这是我发现的一个帖子,因为我试图找到如何编写我自己的联合函数。我知道有一个内置的,但作为一个人谁是试图学习Haskell,这没有任何帮助。这些函数我写了,使其工作。

memberSet :: Int -> [Int] -> Bool 
memberSet x [] = False 
memberSet x (y:ys)
  | x == y = True 
  | otherwise = memberSet x ys

unionSet :: [Int] -> [Int] -> [Int]
unionSet [] [] = []
unionSet (x:xs) [] = (x:xs)
unionSet [] (y:ys) = (y:ys)
unionSet (x:xs) (y:ys)
  | memberSet y (x:xs) = unionSet (x:xs) ys
  | otherwise = y : unionSet (x:xs) ys

main = do
  print (unionSet [1,2,3] [2,5,3,4])

成员集检查一个元素是否存在于一个列表中(我知道有一个内置的函数可以做这个,但是我正在学习)。并集检查第二个列表的第一个元素是否在第一个列表中,如果不在,它就把它添加到一个列表中并递归调用它自己。如果在第一个列表中,它就跳过那个元素并递归调用它自己。

相关问题