Haskell中foldr与foldr1的核心差异咨询
foldr vs foldr1:Haskell折叠操作的核心差异
嘿,完全懂你这种深入研究折叠时突然卡壳的感觉——我当初刚学Haskell时也在这俩家伙身上踩过坑,核心差异其实就俩关键点,给你捋明白:
1. 对空列表的兼容性
这是最直接的区别:
foldr完全支持空列表,因为它需要你传入一个初始值(也就是累加器的起点)。比如:foldr (+) 0 [] -- 返回 0,完美运行 foldr (++) "" [] -- 返回 "",没问题foldr1则完全不能处理空列表,它默认列表至少有一个元素,会用列表的第一个元素作为初始值。如果传空列表,直接触发运行时错误:foldr1 (+) [] -- 报错:Prelude.foldr1: empty list
2. 初始值的来源
这是本质差异:
foldr的初始值是你显式指定的,它的签名是foldr :: (a -> b -> b) -> b -> [a] -> b——第二个参数就是初始值,类型可以和列表元素类型不同(比如上面用""和[String]折叠)。foldr1没有初始值参数,它的签名是foldr1 :: (a -> a -> a) -> [a] -> a——它必须用列表的第一个元素当初始值,所以折叠操作的输入输出类型必须和列表元素类型一致,而且列表不能为空。
举个更直观的例子对比:
-- foldr:用10当初始值,累加所有元素 foldr (+) 10 [1,2,3] -- 计算过程:1 + (2 + (3 + 10)) = 16 -- foldr1:用第一个元素1当初始值,累加剩下的元素 foldr1 (+) [1,2,3] -- 计算过程:1 + (2 + 3) = 6
什么时候用哪个?
- 如果你不能保证列表非空(比如用户输入、过滤后的结果),必须用
foldr,不然程序会炸。 - 如果你确定列表绝对有至少一个元素(比如已经做过非空检查、生成的列表必然非空),用
foldr1更简洁,不用多写一个冗余的初始值。
内容的提问来源于stack exchange,提问作者Madderote
相关产品推荐
相关产品推荐

