截至base 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
会为长列表建立大量的thunk吗?
Num
的实现。例如,可以以这样的方式实现(+)
,使其有时只需要查看第一个元素,并且由于惰性,因此可以在评估整个列表之前终止。 - Willem Van Onsem