Skip to content

Commit 50c0ff0

Browse files
committed
Make 'length' fusible
This change makes fusible 'Data.Vector.Generic.length', which currently can be inlined but doesn't fuse well. Before this revision, 'length' uses non-fusible 'stream''. This revision replaces 'stream'' with fusible 'stream', and at the same time substitute the mutually-recursive occurrences of 'length' with 'basicLength'. Rationale: The current definition was introduced in the commit a811a86. Prior to that commit, 'length' could not even be inlined, because GHC elected it to be a loop-breaker due to the cyclic references among 'stream', 'clone', 'length', and 'unsafeCopy'. This failure of inlining was reported as haskell#97. The commit a811a86 resolved this by replacing 'stream' with 'stream'' in the definition of 'length'. The function 'stream' refers to 'clone' in its fusion rule, but 'stream'' doesn't possess any rule. This cuts open the cycle of references and makes 'length' inlinable. However, since 'stream'' doesn't possess any rule, defining 'length' = 'Bundle.length' . 'stream'' is all the same as setting 'length' = 'basicLength'. This prevents any stream fusion from happening. This commit resolves this problem by resetting 'length' back to be 'Bundle.length' . 'stream', and instead replacing cyclic occurrence of 'length' with 'basicLength' (Just *inlined the simplification result of the definition*). Now 'length' is both inlinable and fusible. Fixes: haskell#306 See also: haskell#97
1 parent eeb42ad commit 50c0ff0

File tree

1 file changed

+5
-11
lines changed

1 file changed

+5
-11
lines changed

Data/Vector/Generic.hs

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ import qualified Data.Traversable as T (Traversable(mapM))
222222
-- | /O(1)/ Yield the length of the vector
223223
length :: Vector v a => v a -> Int
224224
{-# INLINE length #-}
225-
length = Bundle.length . stream'
225+
length = Bundle.length . stream
226226

227227
-- | /O(1)/ Test whether a vector is empty
228228
null :: Vector v a => v a -> Bool
@@ -1986,7 +1986,7 @@ copy
19861986
:: (PrimMonad m, Vector v a) => Mutable v (PrimState m) a -> v a -> m ()
19871987
{-# INLINE copy #-}
19881988
copy dst src = BOUNDS_CHECK(check) "copy" "length mismatch"
1989-
(M.length dst == length src)
1989+
(M.length dst == basicLength src)
19901990
$ unsafeCopy dst src
19911991

19921992
-- | /O(n)/ Copy an immutable vector into a mutable one. The two vectors must
@@ -1995,7 +1995,7 @@ unsafeCopy
19951995
:: (PrimMonad m, Vector v a) => Mutable v (PrimState m) a -> v a -> m ()
19961996
{-# INLINE unsafeCopy #-}
19971997
unsafeCopy dst src = UNSAFE_CHECK(check) "unsafeCopy" "length mismatch"
1998-
(M.length dst == length src)
1998+
(M.length dst == basicLength src)
19991999
$ (dst `seq` src `seq` basicUnsafeCopy dst src)
20002000

20012001
-- Conversions to/from Bundles
@@ -2004,13 +2004,7 @@ unsafeCopy dst src = UNSAFE_CHECK(check) "unsafeCopy" "length mismatch"
20042004
-- | /O(1)/ Convert a vector to a 'Bundle'
20052005
stream :: Vector v a => v a -> Bundle v a
20062006
{-# INLINE_FUSED stream #-}
2007-
stream v = stream' v
2008-
2009-
-- Same as 'stream', but can be used to avoid having a cycle in the dependency
2010-
-- graph of functions, which forces GHC to create a loop breaker.
2011-
stream' :: Vector v a => v a -> Bundle v a
2012-
{-# INLINE stream' #-}
2013-
stream' v = Bundle.fromVector v
2007+
stream v = Bundle.fromVector v
20142008

20152009
{-
20162010
stream v = v `seq` n `seq` (Bundle.unfoldr get 0 `Bundle.sized` Exact n)
@@ -2133,7 +2127,7 @@ clone :: Vector v a => v a -> New v a
21332127
{-# INLINE_FUSED clone #-}
21342128
clone v = v `seq` New.create (
21352129
do
2136-
mv <- M.new (length v)
2130+
mv <- M.new (basicLength v)
21372131
unsafeCopy mv v
21382132
return mv)
21392133

0 commit comments

Comments
 (0)