[GHC] #7994: Make foldl into a good consumer
GHC
ghc-devs at haskell.org
Tue Jun 18 15:20:40 CEST 2013
#7994: Make foldl into a good consumer
---------------------------------+------------------------------------------
Reporter: simonpj | Owner:
Type: bug | Status: new
Priority: normal | Milestone:
Component: Compiler | Version: 7.6.3
Keywords: | Os: Unknown/Multiple
Architecture: Unknown/Multiple | Failure: None/Unknown
Difficulty: Unknown | Testcase:
Blockedby: | Blocking:
Related: |
---------------------------------+------------------------------------------
I really want `foldl` to be a good consumer, but our arity/cardinality
analysis still isn't up to it. Here's a test case, derived from nofib's
`x2n1`:
{{{
module Foo( foo ) where
import Data.Complex
foo x = sum [f n | n <- [1 .. x]]
f :: Int -> Complex Double
{-# NOINLINE f #-}
f n = mkPolar 1 ((2*pi)/fromIntegral n) ^ n
}}}
With the patch below (which is what I'd like to use), we get very
obviously bad code:
{{{
Foo.foo :: GHC.Types.Int -> Data.Complex.Complex GHC.Types.Double
Foo.foo =
\ (x_aia :: GHC.Types.Int) ->
case x_aia of _ { GHC.Types.I# y_aye ->
case GHC.Prim.># 1 y_aye of _ {
GHC.Types.False ->
letrec {
go_aD8 [Occ=LoopBreaker]
:: GHC.Prim.Int#
-> Data.Complex.Complex GHC.Types.Double
-> Data.Complex.Complex GHC.Types.Double
go_aD8 =
\ (x_aD9 :: GHC.Prim.Int#) ->
let {
ds_doR [Lbv=OneShot]
:: Data.Complex.Complex GHC.Types.Double
-> Data.Complex.Complex GHC.Types.Double
ds_doR =
case GHC.Prim.==# x_aD9 y_aye of _ {
GHC.Types.False -> go_aD8 (GHC.Prim.+# x_aD9 1);
GHC.Types.True ->
GHC.Base.id @ (Data.Complex.Complex
GHC.Types.Double)
} } in
let {
ds_aCs :: Data.Complex.Complex GHC.Types.Double
ds_aCs = Foo.f (GHC.Types.I# x_aD9) } in
\ (ds2_aCu :: Data.Complex.Complex GHC.Types.Double) ->
ds_doR (Data.Complex.$fFloatingComplex_$s$c+ ds2_aCu
ds_aCs); } in
go_aD8
1
(Data.Complex.:+
@ GHC.Types.Double
(GHC.Types.D# 0.0)
Data.Complex.$fFloatingComplex1);
GHC.Types.True ->
Data.Complex.:+
@ GHC.Types.Double
(GHC.Types.D# 0.0)
Data.Complex.$fFloatingComplex1 } }
}}}
The local `go` function should have arity 2.
The patch below is the one I'd like to apply to `base`:
{{{
simonpj at cam-05-unx:~/code/HEAD/libraries/base$ git diff
diff --git a/Data/List.hs b/Data/List.hs
index e7e8602..a2e7ac0 100644
--- a/Data/List.hs
+++ b/Data/List.hs
@@ -1,5 +1,5 @@
{-# LANGUAGE Trustworthy #-}
-{-# LANGUAGE CPP, NoImplicitPrelude, MagicHash #-}
+{-# LANGUAGE CPP, NoImplicitPrelude, ScopedTypeVariables, MagicHash #-}
-----------------------------------------------------------------------------
-- |
@@ -995,11 +995,15 @@ unfoldr f b =
--
-----------------------------------------------------------------------------
-- | A strict version of 'foldl'.
-foldl' :: (b -> a -> b) -> b -> [a] -> b
+foldl' :: forall a b. (b -> a -> b) -> b -> [a] -> b
#ifdef __GLASGOW_HASKELL__
+{-# INLINE foldl' #-}
+foldl' k z xs = foldr (\(v::a) (fn::b->b) (z::b) -> z `seq` fn (k z v))
(id :: b -> b) xs z
+{-
foldl' f z0 xs0 = lgo z0 xs0
where lgo z [] = z
lgo z (x:xs) = let z' = f z x in z' `seq` lgo z' xs
+-}
#else
foldl' f a [] = a
foldl' f a (x:xs) = let a' = f a x in a' `seq` foldl' f a' xs
@@ -1022,6 +1026,17 @@ foldl1' _ [] = errorEmptyList
"foldl1'"
--
-----------------------------------------------------------------------------
-- List sum and product
+-- | The 'sum' function computes the sum of a finite list of numbers.
+sum :: (Num a) => [a] -> a
+-- | The 'product' function computes the product of a finite list of
numbers.
+product :: (Num a) => [a] -> a
+
+{-# INLINE sum #-}
+sum = foldl (+) 0
+{-# INLINE product #-}
+product = foldl (*) 1
+
+{-
{-# SPECIALISE sum :: [Int] -> Int #-}
{-# SPECIALISE sum :: [Integer] -> Integer #-}
{-# INLINABLE sum #-}
@@ -1048,6 +1063,7 @@ product l = prod l 1
prod [] a = a
prod (x:xs) a = prod xs (a*x)
#endif
+-}
--
-----------------------------------------------------------------------------
-- Functions on strings
diff --git a/GHC/List.lhs b/GHC/List.lhs
index 049aa2a..87c93ae 100644
--- a/GHC/List.lhs
+++ b/GHC/List.lhs
@@ -1,6 +1,6 @@
\begin{code}
{-# LANGUAGE Trustworthy #-}
-{-# LANGUAGE CPP, NoImplicitPrelude, MagicHash #-}
+{-# LANGUAGE CPP, NoImplicitPrelude, ScopedTypeVariables, MagicHash #-}
{-# OPTIONS_HADDOCK hide #-}
-----------------------------------------------------------------------------
@@ -179,11 +179,17 @@ filterFB c p x r | p x = x `c` r
-- can be inlined, and then (often) strictness-analysed,
-- and hence the classic space leak on foldl (+) 0 xs
+foldl :: forall a b. (b -> a -> b) -> b -> [a] -> b
+{-# INLINE foldl #-}
+foldl k z xs = foldr (\(v::a) (fn::b->b) (z::b) -> fn (k z v)) (id :: b
-> b) xs z
+
+{-
foldl :: (b -> a -> b) -> b -> [a] -> b
foldl f z0 xs0 = lgo z0 xs0
where
lgo z [] = z
lgo z (x:xs) = lgo (f z x) xs
+-}
-- | 'scanl' is similar to 'foldl', but returns a list of successive
-- reduced values from the left:
}}}
--
Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/7994>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list