我一直在用Haskell编写代码,但无法理解实现联合函数的想法。我也发现了一些嵌入在Haskell平台中的函数定义。但问题是我需要一个简洁易懂的方法来使其工作。有人能帮助我吗?
vh0rcniy1#
假设你在讨论union :: Eq a => [a] -> [a] -> [a],它接受两个输入列表,并返回第三个列表,其中包含每个参数列表的所有元素,那么它在base包中的Data.List中定义。在源代码中,它被分为两个函数,广义函数unionBy接受等式的自定义定义定义(类型等于(==) :: a -> a -> Bool的函数),然后通过传入(==)作为等式的具体实现来定义使用Eq类型类的函数。
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
在deleteBy和nubBy中的unionBy的定义中,同样的模式又出现了两次,这两个函数都遵循相同的约定。delete从列表中删除一个元素,而nub返回一个唯一元素的列表。我们'我将再次简化定义以消除(==)的所有痕迹,并简单地假设元素a具有定义的Eq。
deleteBy
nubBy
delete
nub
a
union xs ys = xs ++ foldl (flip delete) (nub ys) xs
xs和ys的union是xs附加到唯一的(“nub床”)已由foldl (flip delete) _ xs处理的ys的值。得出foldl的最终结果是要逐一尝试将delete中的每个元素xs从(nub ys)中取出。这意味着,union xs ys是xs,它附加到ys中的每个唯一元素上,减去xs中的元素。顺便说一句,通过这个源代码,我们可以注意到union的一些古怪行为,比如它如何将第一个参数中的重复项与第二个参数中的重复项区别对待
xs
ys
union
foldl (flip delete) _ xs
foldl
(nub ys)
union xs ys
union [1,1,2] [2] == [1,1,2] union [2] [1,1,2] == [2,1]
这有点令人失望,因为使用[]来表示类似Set的union概念的结果。
[]
Set
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代码的强大工具。不要害怕通过手动内联函数的定义来直接简化代码。
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
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])
成员集检查一个元素是否存在于一个列表中(我知道有一个内置的函数可以做这个,但是我正在学习)。并集检查第二个列表的第一个元素是否在第一个列表中,如果不在,它就把它添加到一个列表中并递归调用它自己。如果在第一个列表中,它就跳过那个元素并递归调用它自己。
3条答案
按热度按时间vh0rcniy1#
假设你在讨论
union :: Eq a => [a] -> [a] -> [a]
,它接受两个输入列表,并返回第三个列表,其中包含每个参数列表的所有元素,那么它在base
包中的Data.List
中定义。在源代码中,它被分为两个函数,广义函数
unionBy
接受等式的自定义定义定义(类型等于(==) :: a -> a -> Bool
的函数),然后通过传入(==)
作为等式的具体实现来定义使用Eq
类型类的函数。不过,我们可以把
(==)
替换成unionBy
代码,就像 haskell 让我们使用等式推理一样。在
deleteBy
和nubBy
中的unionBy
的定义中,同样的模式又出现了两次,这两个函数都遵循相同的约定。delete
从列表中删除一个元素,而nub
返回一个唯一元素的列表。我们'我将再次简化定义以消除(==)
的所有痕迹,并简单地假设元素a
具有定义的Eq
。xs
和ys
的union
是xs
附加到唯一的(“nub
床”)已由foldl (flip delete) _ xs
处理的ys
的值。得出foldl
的最终结果是要逐一尝试将delete
中的每个元素xs
从(nub ys)
中取出。这意味着,union xs ys
是xs
,它附加到ys
中的每个唯一元素上,减去xs
中的元素。顺便说一句,通过这个源代码,我们可以注意到
union
的一些古怪行为,比如它如何将第一个参数中的重复项与第二个参数中的重复项区别对待这有点令人失望,因为使用
[]
来表示类似Set
的union
概念的结果。这也给了我们
union
的另一个定义那么,
foldl
是如何运作的呢?让我们来看看foldl
的定义,同样是滥用等式推理。这将使该技巧更加明显-它在
xs
的元素上循环,将它们从(nub ys)
中逐个删除。虽然希望这有助于使
union
中的代码更清晰一些,但真实的的收获应该是等式推理是剖析Haskell代码的强大工具。不要害怕通过手动内联函数的定义来直接简化代码。ijnw1ujt2#
我不确定这个
union
是否符合您的要求,但它相当简单。我需要自己的函数来删除重复项。它的作用与任何具有相同目的的递归函数相同。
yrdbyhpb3#
我可能误解了这个问题,但这是我发现的一个帖子,因为我试图找到如何编写我自己的联合函数。我知道有一个内置的,但作为一个人谁是试图学习Haskell,这没有任何帮助。这些函数我写了,使其工作。
成员集检查一个元素是否存在于一个列表中(我知道有一个内置的函数可以做这个,但是我正在学习)。并集检查第二个列表的第一个元素是否在第一个列表中,如果不在,它就把它添加到一个列表中并递归调用它自己。如果在第一个列表中,它就跳过那个元素并递归调用它自己。