关于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
相关产品推荐
相关产品推荐

