Commit 90c9c835 authored by Simon Peyton Jones's avatar Simon Peyton Jones
Browse files

Make 'length' into a good consumer, fixing Trac #876

Trac #876 is the oldest ticket I have fixed in a long time.
I finally figured out how to make foldr behave in a non
space-leaky way for length.

Thanks to Andy for re-opening.
parent c301c614
...@@ -114,12 +114,25 @@ null (_:_) = False ...@@ -114,12 +114,25 @@ null (_:_) = False
-- | /O(n)/. 'length' returns the length of a finite list as an 'Int'. -- | /O(n)/. 'length' returns the length of a finite list as an 'Int'.
-- It is an instance of the more general 'Data.List.genericLength', -- It is an instance of the more general 'Data.List.genericLength',
-- the result type of which may be any kind of number. -- the result type of which may be any kind of number.
{-# NOINLINE [1] length #-}
length :: [a] -> Int length :: [a] -> Int
length l = len l 0# length l = lenAcc l 0#
where
len :: [a] -> Int# -> Int lenAcc :: [a] -> Int# -> Int
len [] a# = I# a# lenAcc [] a# = I# a#
len (_:xs) a# = len xs (a# +# 1#) lenAcc (_:xs) a# = lenAcc xs (a# +# 1#)
incLen :: a -> (Int# -> Int) -> Int# -> Int
incLen _ g x = g (x +# 1#)
-- These rules make length into a good consumer
-- Note that we use a higher-order-style use of foldr, so that
-- the accumulating parameter can be evaluated strictly
-- See Trac #876 for what goes wrong otherwise
{-# RULES
"length" [~1] forall xs. length xs = foldr incLen I# xs 0#
"lengthList" [1] foldr incLen I# = lenAcc
#-}
-- | 'filter', applied to a predicate and a list, returns the list of -- | 'filter', applied to a predicate and a list, returns the list of
-- those elements that satisfy the predicate; i.e., -- those elements that satisfy the predicate; i.e.,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment