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
不会为长列表积累大量的东西吗?
答案 0 :(得分:14)
genericLength
在实现时考虑了Peano数:
data Peano = Zero | Succ Peano
使用此表示形式的数字可以是非严格的,因此类似genericLength [1..] > 5
的操作将返回True而不是终止。
对于Num的大多数其他合理实现,genericLength
中的文件夹确实会引起您提到的问题。