【发布时间】:2019-05-10 03:17:50
【问题描述】:
考虑从列表中删除连续重复项的函数的以下实现之一:
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
它们在有限和无限列表上都按预期工作。更具体地说,对于无限列表,只要在返回 n 值之前没有无限长的重复值序列,我希望 take n $ uniq l 终止。
现在考虑这个函数的尝试,使用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 来解决的问题,还是本来就不可能使用折叠来完成这项任务?
【问题讨论】:
-
“按预期工作”是指
uniq (let ones = 1:ones in ones)永远不会终止吗?您的第一个只有在找到一对不同的相邻元素时才会终止。 -
@chepner 很好。我希望
head $ uniq $ repeat 1确实返回1。不过,接受的答案可以正确处理。 -
@chepner 我的非折叠示例现在适用于这种情况。
-
foldl应该更好,但你也可以像map head . group一样使用无限列表。 -
不像
foldl',foldl是懒惰的,所以我想终止应该没有问题。
标签: haskell fold infinite-sequence