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

Haskell惰性求值下anyBig函数的GHC求值顺序探究

Haskell惰性求值的实际行为分析

Haskell的惰性求值是否有用或存在风险,取决于计算瓶颈是时间复杂度还是栈大小。为了更深入理解Haskell的求值机制,我们来看下面的示例:

首先定义简单函数:

isBig :: Int -> Bool
isBig = (<=) 5

基于此,我们定义判断列表中是否存在大数的函数:

anyBig :: [Int] -> Bool
anyBig = or . map isBig

按照惰性求值的特性,传入[7,1,2,1]时,理论上只需要调用一次isBig就能返回True。我们来梳理GHC可能的求值顺序:

anyBig [7,1,2,1]                                    -- 开始
(or . map isBig) [7,1,2,1]                          -- 展开anyBig的定义
or $ map isBig [7,1,2,1]                            -- 展开函数组合(.)的定义
foldr (||) False $ isBig 7 : map isBig [1,2,1]      -- 展开or和map的定义(顺序不定)
False || foldr (||) (isBig 7) (map isBig [1,2,1])   -- 展开foldr的定义
foldr (||) (isBig 7) (map isBig [1,2,1])            -- 展开||的定义(False || x = x)

此时,存在两种求值可能性:

  • 可能性1:GHC足够智能,识别出唯一阻碍模式匹配的是最后一个参数,因此执行:
foldr (||) (isBig 7) (isBig 1 : map isBig [2,1])     -- 展开map的定义
(isBig 7) || foldr (||) (isBig 1) (map isBig [2,1])  -- 展开foldr的定义
  • 可能性2:GHC因无匹配项,会在同一层级求值所有内容:
foldr (||) True (isBig 1 : map isBig [2,1])          -- 展开map的定义,同时求值isBig 7得到True
True || foldr (||) (isBig 1) (map isBig [2,1])       -- 展开foldr的定义

在情况2中,根据||的定义(True || _ = True),计算会立即终止并返回True。但在情况1中,不确定GHC会优先展开map得到:

(isBig 7) || (isBig 1) || (isBig 2) || (isBig 1) 

还是会先求值isBig 7,像情况2那样直接返回结果。另外,假设最终得到上述表达式,由于||是右结合(infixr),如果从右侧开始计算,反而会达到最慢的速度。

内容的提问来源于stack exchange,提问作者MannyC

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 01:25:27