[commit: base] master: Make 'length' into a good consumer, fixing Trac #876 (82f56e5)

Simon Peyton Jones simonpj at microsoft.com
Thu Feb 14 09:33:01 CET 2013


Repository : ssh://darcs.haskell.org//srv/darcs/packages/base

On branch  : master

http://hackage.haskell.org/trac/ghc/changeset/82f56e5a331f9bbd5c8afda9e8d8ad71059e934b

>---------------------------------------------------------------

commit 82f56e5a331f9bbd5c8afda9e8d8ad71059e934b
Author: Simon Peyton Jones <simonpj at microsoft.com>
Date:   Thu Feb 14 08:22:08 2013 +0000

    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.

>---------------------------------------------------------------

 GHC/List.lhs |   23 ++++++++++++++++++-----
 1 files changed, 18 insertions(+), 5 deletions(-)

diff --git a/GHC/List.lhs b/GHC/List.lhs
index 02d6965..049aa2a 100644
--- a/GHC/List.lhs
+++ b/GHC/List.lhs
@@ -114,12 +114,25 @@ null (_:_)              =  False
 -- | /O(n)/. 'length' returns the length of a finite list as an 'Int'.
 -- It is an instance of the more general 'Data.List.genericLength',
 -- the result type of which may be any kind of number.
+{-# NOINLINE [1] length #-}
 length                  :: [a] -> Int
-length l                =  len l 0#
-  where
-    len :: [a] -> Int# -> Int
-    len []     a# = I# a#
-    len (_:xs) a# = len xs (a# +# 1#)
+length l                =  lenAcc l 0#
+
+lenAcc :: [a] -> Int# -> Int
+lenAcc []     a# = I# a#
+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
 -- those elements that satisfy the predicate; i.e.,





More information about the ghc-commits mailing list