为什么foldl1无法应用(==)运算符?

时间:2011-02-06 00:08:45

标签: haskell functional-programming higher-order-functions fold

来自前奏

  

foldl1 :它需要前两项   列表并将函数应用于   他们,然后提供功能   这个结果和第三个论点和   等等。

为什么不能写这样的东西?

foldl1 (==) [6, 6, 6]
foldl1 (\x y -> x == y) [6, 6, 6]

4 个答案:

答案 0 :(得分:5)

如果要检查列表中的所有元素是否相同,可以使用快速解决方案

allEqual [] = True --(edit: this case is not necessary as pointed out by sepp2k)
allEqual xs = all (== head xs) xs

我确信有人会写一种更优雅的方法来做到这一点,但这是可用的。

编辑:感谢sepp2k的建议。

答案 1 :(得分:2)

编辑:安塔尔指出我的推理是不正确的。这是评论的相关部分,给出了真正的推理(我逐字逐句地感觉不好,但这个答案被接受了,所以我不能删除它):

这不起作用的原因是foldl1的类型为(a -> a -> a) -> [a] -> a,但(==)的类型为Num a => a -> a -> Bool。由于Bool不是Num(==)类型与a -> a -> a不匹配,因此foldl1的申请被拒绝。如果它被接受了,你最终会遇到一个你试图做True == 6的情况,但类型系统从来没有让你在第一时间走得那么远。

原始答案(后一种推理不正确):

==将花费两个Int并返回Bool。第一次迭代后,您的示例列表变为[True, 6]。然后,它会尝试将失败的True6进行比较。

答案 2 :(得分:1)

这是另一个版本:

allEqual xs = and $ zipWith (==) xs (tail xs)

答案 3 :(得分:0)

如果您想使用折叠,我建议您进行此修改:

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折叠步骤。