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

关于Haskell中findIndices函数双版本源码的理解咨询

解读Haskell中findIndices函数的双版本源码

我之前对着findIndices的源码摸不着头脑,直到突然反应过来——这个函数居然有两种不同的实现定义!这就是我一开始没看明白的核心原因。

先明确函数的类型签名,它的作用是找出列表中所有满足谓词的元素的索引:

findIndices :: (a -> Bool) -> [a] -> [Int]

接下来分两种场景看具体实现:

1. 简洁直观的报告标准实现(开启USE_REPORT_PRELUDE时)

当编译时定义了USE_REPORT_PRELUDE宏,就会使用这个用列表推导式写的版本,逻辑直白到一眼就能懂:

#if defined(USE_REPORT_PRELUDE)
findIndices p xs = [ i | (x,i) <- zip xs [0..], p x]
#endif

简单说就是把列表里的每个元素和它的索引配对,过滤出满足条件p x的项,最后把对应的索引收集起来形成结果列表。

2. 性能优先的高效实现(默认版本)

如果没开启上述宏,就会启用这个从Data.Sequence改编来的优化版本,用了Haskell里的列表融合技巧,目的是减少中间列表的生成,提升运行效率:

#else
-- Efficient definition, adapted from Data.Sequence
{-# INLINE findIndices #-}
findIndices p ls = build $ \c n -> let 
    go x r k 
        | p x       = I# k `c` r (k +# 1#) 
        | otherwise = r (k +# 1#) 
    in foldr go (\_ -> n) ls 0#
#endif

这个版本用foldr遍历列表,结合build函数直接构造结果列表,避免了像第一个版本那样生成zip xs [0..]这样的中间列表,所以代码看起来会复杂一些,但性能表现更好。

内容的提问来源于stack exchange,提问作者Stéphane Laurent

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:42:47