从4.12版本开始,genericLength
实现为:
genericLength :: (Num i) => [a] -> i
{-# NOINLINE [1] genericLength #-}
genericLength [] = 0
genericLength (_:l) = 1 + genericLength l
{-# RULES
"genericLengthInt" genericLength = (strictGenericLength :: [a] -> Int);
"genericLengthInteger" genericLength = (strictGenericLength :: [a] -> Integer);
#-}
strictGenericLength :: (Num i) => [b] -> i
strictGenericLength l = gl l 0
where
gl [] a = a
gl (_:xs) a = let a' = a + 1 in a' `seq` gl xs a'
这基本上是
foldr
,除了Int
和Integer
之外,它执行的是foldl'
。为什么在所有情况下都不使用
foldl'
? foldr
不会为长列表建立大量的功能吗? 最佳答案
实现genericLength
时要牢记Peano数字:
data Peano = Zero | Succ Peano
使用此表示形式的数字可以是非严格的,因此像
genericLength [1..] > 5
这样的操作将返回True而不是失败终止。对于Num的大多数其他合理实现,
genericLength
中的文件夹确实确实会引起您提到的问题。