You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Haskell中foldr与foldl应用div函数的计算逻辑问询

解惑Haskell的foldr/foldl:为什么div折叠只返回一个值?

嘿,我完全懂你这种困惑!当初我刚学Haskell的fold系列函数时,也对着类似的问题挠头好久——明明加法折叠的替换逻辑能理解,怎么一换div就完全不是预期的结果?咱们一步步掰扯清楚:

首先纠正核心误解:fold是「归约」,不是「映射」

你之所以以为会得到“每个元素除以7的列表”,是不小心把fold和map的作用搞混了:

  • map是映射操作:给列表里的每个元素都套上同一个函数,输出一个和原列表长度相同的新列表,比如map (\x -> x div 7) [1,2,3]才会返回[0,0,0],这是你预期的“每个元素除以7”的效果。
  • 而foldr/foldl是归约操作:它们的目标是把整个列表的所有元素,通过你传入的二元函数,一步步“折叠”合并成单一值——从始至终,它们都不会生成新列表,只会输出一个结果。

拿你的div折叠例子,一步步看GHCi的计算过程

假设你在GHCi里输入的是类似foldr (div) 7 [1,2,3]或者foldl (div) 7 [1,2,3],咱们分别拆解:

情况1:foldr div 7 [1,2,3]

foldr的核心逻辑是右结合,从列表的末尾开始往回计算,公式是:
foldr f z [x1,x2,x3] = f x1 (f x2 (f x3 z))

代入你的例子,展开后是:

div 1 (div 2 (div 3 7))

现在一步步计算:

  1. 最内层:div 3 7——Haskell的div是整数除法,正数相除会截断向零,3除以7商0,所以这一步结果是0。
  2. 中间层:div 2 0——这里直接触发除以零错误,GHCi会抛出*** Exception: divide by zero。

情况2:foldl div 7 [1,2,3]

foldl是左结合,从列表的开头往前计算,公式是:
foldl f z [x1,x2,x3] = f (f (f z x1) x2) x3

代入例子展开后是:

div (div (div 7 1) 2) 3

计算过程:

  1. 最内层:div 7 1 = 7
  2. 中间层:div 7 2 = 3(整数除法,7除以2商3)
  3. 最外层:div 3 3 = 1
    最终GHCi会输出1——这就是你看到的“只得到一个元素”的原因,它本来就只会返回单一值。

再回顾你理解的加法折叠,验证归约逻辑

你之前懂的foldr (+) 0 [1,2,3],展开是1 + (2 + (3 + 0)),最终得到6——这也是一个单一值,只是加法的场景下,你可能默认接受“求和得到一个数”,但换了div就忘了fold的本质是归约。

总结一下

如果你的目标是给列表每个元素做转换生成新列表,用map;如果是要把列表所有元素合并成一个值(求和、求积、找最大值、拼接字符串等),才用foldr/foldl。搞清楚这两类函数的定位,就不会再出现这种预期偏差啦~

内容的提问来源于stack exchange,提问作者Pape Sow Traore

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 07:46:43