从前奏:
foldl1:它获取列表的前两项并将函数应用于它们,然后将这个结果和第三个参数提供给函数,依此类推。
为什么不能写这样的东西?
foldl1 (==) [6, 6, 6]
foldl1 (\x y -> x == y) [6, 6, 6]
从前奏:
foldl1:它获取列表的前两项并将函数应用于它们,然后将这个结果和第三个参数提供给函数,依此类推。
为什么不能写这样的东西?
foldl1 (==) [6, 6, 6]
foldl1 (\x y -> x == y) [6, 6, 6]
如果要检查列表的所有元素是否相等,一个快速的解决方案是
allEqual [] = True --(edit: this case is not necessary as pointed out by sepp2k)
allEqual xs = all (== head xs) xs
我敢肯定,有人会写一个更优雅的方式来做到这一点,但这是有用的。
编辑:感谢 sepp2k 的建议。
编辑:Antal 指出我的推理不正确。这是评论的相关部分,它给出了真正的推理(我觉得这个逐字记录很糟糕,但这个答案被接受了,所以我不能删除它):
这不起作用的原因是类型foldl1
是(a -> a -> a) -> [a] -> a
,但类型(==)
是Num a => a -> a -> Bool
。由于Bool
is not a Num
,(==)
type 不匹配a -> a -> a
,所以申请 offoldl1
被拒绝。如果它被接受,你最终会遇到你试图做的情况True == 6
,但类型系统一开始就永远不会让你走得那么远。
原始答案(后来的推理不正确):
==
将需要两个Int
s 并返回 a Bool
。第一次迭代后,您的示例列表变为[True, 6]
. 然后它尝试比较True
哪个6
失败。
这是另一个版本:
allEqual xs = and $ zipWith (==) xs (tail xs)
如果您想使用折叠,我建议您进行以下修改:
allEqual xs = foldr (\x acc -> x == head xs && acc) True xs
这与已经建议的方法非常相似all
。请注意,这和all
方法都可以在无限列表上工作(只要答案是False
)。
对于非常长的有限列表,在极少数情况下,您可能会从严格的左折叠中获得更好的性能:
allEqual xs = foldl' (\acc x -> acc && x == head xs) True xs
但是对于这个问题,正确的折叠通常更好,因为(在这个实现中)它只执行等于 的折叠步骤length $ takeWhile (== head xs) xs
。左length xs
折叠每次都会执行折叠步骤。