考虑从列表中删除连续重复项的函数的以下实现之一:
uniq :: Eq a => [a] -> [a]
uniq [] = []
uniq (x:xs) = x:uniq (dropWhile (x ==) xs)
uniq :: Eq a => [a] -> [a]
uniq (x:xs@(y:_))
| x == y = x:tail (uniq xs)
| otherwise = x:uniq xs
uniq l = l
它们在有限和无限列表上都按预期工作。更具体地说,对于无限列表,take n $ uniq l
只要在n
返回值之前没有无限长的重复值序列,我就希望终止。
现在考虑这种功能的尝试,使用foldr
:
uniq :: (Foldable t, Eq a) => t a -> [a]
uniq = foldr uniqHelper []
where uniqHelper x [] = [x]
uniqHelper x acc@(y:_)
| x == y = acc
| otherwise = x:acc
这在有限列表上正常工作,但永远不会因无限列表而终止,因为uniqHelper
总是需要评估它的第二个参数。这是可以用更聪明的方法解决的uniqHelper
问题,还是本来就不可能使用折叠来完成这项任务?