为什么将Data.List.genericLength实现为正确的折叠?

时间:2019-05-15 21:13:14

标签: haskell

从基础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不会为长列表积累大量的东西吗?

1 个答案:

答案 0 :(得分:14)

genericLength在实现时考虑了Peano数:

data Peano = Zero | Succ Peano

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

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