从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,除了IntInteger之外,它执行的是foldl'

为什么在所有情况下都不使用foldl'foldr不会为长列表建立大量的功能吗?

最佳答案

实现genericLength时要牢记Peano数字:

data Peano = Zero | Succ Peano

使用此表示形式的数字可以是非严格的,因此像genericLength [1..] > 5这样的操作将返回True而不是失败终止。

对于Num的大多数其他合理实现,genericLength中的文件夹确实确实会引起您提到的问题。

10-08 12:35