关于Haskell中foldl求和实现where部分变量作用的疑问
理解Haskell中foldl实现求和的工作机制
首先纠正代码里的一个小细节:Haskell中函数名必须小写,所以Sum应该改成sum,修正后的代码是:
sum :: [Int] -> Int sum xs = foldl f base xs where f a x = (+) a x base = 0
先搞懂foldl的基本逻辑
foldl是Haskell里的左折叠函数,它的作用是把一个二元函数"折叠"到列表的每个元素上,最终得到一个单一值。它的类型签名是:
foldl :: (b -> a -> b) -> b -> [a] -> b
拆解一下:
- 第一个参数:一个二元函数,接收累加器(类型b)和列表当前元素(类型a),返回更新后的累加器(类型b)
- 第二个参数:累加器的初始值(类型b)
- 第三个参数:要处理的列表(类型[a])
- 返回值:最终的累加结果(类型b)
在求和代码里,b和a都是Int,所以foldl在这里的类型是(Int -> Int -> Int) -> Int -> [Int] -> Int。
详解f a x的作用
你之前的误解是把它当成了模式匹配,但其实f就是foldl需要的那个二元函数:
a是当前的累加器值:一开始是base=0,之后每一步都会变成上一次计算的结果x是列表里正在处理的单个元素:每次遍历列表时取一个元素传入f a x = (+) a x等价于f a x = a + x,作用就是把当前元素加到累加器上,返回新的累加器值
用具体例子模拟执行过程
拿列表[1,2,3]来一步步看:
- 初始状态:累加器
a=0,处理第一个元素x=1,调用f 0 1,得到0+1=1 - 累加器更新为
1,处理第二个元素x=2,调用f 1 2,得到1+2=3 - 累加器更新为
3,处理第三个元素x=3,调用f 3 3,得到3+3=6 - 列表遍历完毕,返回最终的累加器值
6
关于简化写法的补充
你提到有更简便的实现,其实f完全可以直接用(+)替代,因为(+)本身就是一个接收两个Int、返回Int的二元函数,所以代码可以简化成:
sum :: [Int] -> Int sum xs = foldl (+) 0 xs
甚至利用Haskell的柯里化特性,进一步写成:
sum :: [Int] -> Int sum = foldl (+) 0
内容的提问来源于stack exchange,提问作者sharkman99
相关产品推荐
相关产品推荐

