Haskell中foldr/foldl作用于二元组时为何忽略首个元组元素?
问题描述
我在测试中观察到如下现象:
foldr (+) 0 (3,7) 7 foldl (+) 0 (3,7) 7
测试环境版本信息:
ghci --version The Glorious Glasgow Haskell Compilation System, version 9.2.2
请问上述运行结果是否为符合语言设计的预期行为?该行为背后的设计原理是什么?
解答
这个运行结果完全是符合Haskell语言设计预期的正常行为,不是编译器bug。
背后的核心设计逻辑和Foldable类型类的二元组实例规则直接相关:
- Haskell中二元组类型
(a,b)的Foldable实例,是将二元组定义为「携带一个固定类型附加注解的单元素容器」:容器内参与折叠遍历的元素只有第二个字段,第一个字段属于容器本身附带的上下文信息,折叠时会被直接忽略。 - 这个设计的合理性来自类型约束:二元组的两个字段类型可以完全无关,比如
(String, Int)类型的二元组,第一个字段是字符串,根本无法和数值类型的初始值、累加值做加法运算。如果要求折叠操作同时处理两个字段,根本无法写出类型通用的折叠实现。
你可以用几个简单的测试验证这个规则:
-- 第一个字段不管是什么值,都不会参与折叠计算 foldr (+) 100 (9999, 5) -- 结果为105,即100 + 5 foldl (*) 2 ("任意字符串", 4) -- 结果为8,即2 * 4
回到给出的测试用例:(3,7)的第一个字段3会被折叠逻辑直接跳过,不管是右折叠foldr还是左折叠foldl,都只会取第二个字段7和初始值0做加法运算,0 + 7 = 7,因此两个表达式的输出结果一致。
如果需要对二元组的两个字段同时做聚合计算,不能直接使用通用的foldr/foldl,需要手动取两个字段完成计算,或者使用适配二元组的专用运算函数。
内容的提问来源于stack exchange,提问作者stf
相关产品推荐
相关产品推荐

