@@ -102,7 +102,7 @@ import Foreign.Storable (Storable(..))
102102import Prelude hiding (length, foldr, read, unlines, splitAt)
103103import Text.Read (readPrec, readListPrec, readListPrecDefault)
104104
105−import GHC.Base (Addr#, nullAddr#, realWorld#)
105+import GHC.Base (Addr#, nullAddr#, realWorld#, build)
106106import GHC.Exts (IsList, IsString(..))
107107import GHC.ForeignPtr (ForeignPtr(..), newForeignPtr_)
108108import GHC.IO (IO(IO), unsafePerformIO)
@@ -738,12 +738,33 @@ fromStreamD m = runFold write m
738738 runFold (Fold step begin done) = D.foldlMx' step begin done
739739-}
740740
741+-- Use foldr/build fusion to fuse with list consumers
742+-- This can be useful when using the IsList instance
743+{-# INLINE_LATE toListFB #-}
744+toListFB :: forall a b. Storable a => (a -> b -> b) -> b -> Array a -> b
745+toListFB c n Array{..} = go (unsafeForeignPtrToPtr aStart)
746+ where
747+
748+ go p | p == aEnd = n
749+ go p =
750+ -- unsafeInlineIO allows us to run this in Identity monad for pure
751+ -- toList/foldr case which makes them much faster due to not
752+ -- accumulating the list and fusing better with the pure consumers.
753+ --
754+ -- This should be safe as the array contents are guaranteed to be
755+ -- evaluated/written to before we peek at them.
756+ let !x = unsafeInlineIO $ do
757+ r <- peek p
758+ touchForeignPtr aStart
759+ return r
760+ in c x (go (p `plusPtr` (sizeOf (undefined :: a))))
761+
741762-- | Convert an 'Array' into a list.
742763--
743764-- @since 0.7.0
744−{-# INLINABLE toList #-}
765+{-# INLINE toList #-}
745766toList :: Storable a => Array a -> [a]
746−toList = foldr (:) []
767+toList s = build (\c n -> toListFB c n s)
747768
748769instance (Show a, Storable a) => Show (Array a) where
749770 {-# INLINE showsPrec #-}