on master help sign in
Use unfolds instead of streams for array reading
58d1d61Harendra Kumar
Changelog.md+4−4
@@ -30,7 +30,8 @@
30 add newlines to a stream, `Streamly.Data.String.encodeUtf8` for encoding and
30 add newlines to a stream, `Streamly.Data.String.encodeUtf8` for encoding and
31 `Streamly.FileSystem.Handle.write` for writing to a file handle.
31 `Streamly.FileSystem.Handle.write` for writing to a file handle.
32 * Deprecate `scanx`, `foldx`, `foldxM`, `foldr1`
32 * Deprecate `scanx`, `foldx`, `foldxM`, `foldr1`
33− * Remove deprecated APIs `scan`, `foldl`, `foldlM`
33+ * Remove deprecated APIs `foldl`, `foldlM`
34+ * Replace deprecated API `scan` with a new signature, to scan using Fold.
34
35
35* In `Streamly` module:
36* In `Streamly` module:
36 * `runStream` has been deprecated, please use `Streamly.Prelude.drain`
37 * `runStream` has been deprecated, please use `Streamly.Prelude.drain`
@@ -87,11 +88,10 @@ example, concat streams concurrently using this.
87 character streams and other character stream operations.
88 character streams and other character stream operations.
88 * _Arrays_: `Streamly.Memory.Array` module provides arrays for efficient
89 * _Arrays_: `Streamly.Memory.Array` module provides arrays for efficient
89 in-memory buffering and efficient interfacing with IO.
90 in-memory buffering and efficient interfacing with IO.
90− * `Streamly.Memory.ArrayStream` module provide combinators to work on streams
91− of arrays.
92
91
93* Add the following to `Streamly.Prelude`:
92* Add the following to `Streamly.Prelude`:
94− * `runFold`, `runScan` and `runPostscan`
93+ * `unfold`, `fold`, `scan` and `postscan`
94+ * `concatUnfold` to concat a stream after unfolding each element
95 * `intervalsOf` and `chunksOf`
95 * `intervalsOf` and `chunksOf`
96 * `splitOn`, `splitOnSuffix`, `splitWithSuffix`, and `wordsBy`
96 * `splitOn`, `splitOnSuffix`, `splitWithSuffix`, and `wordsBy`
97 * `groups`, `groupsBy` and `groupsByRolling`
97 * `groups`, `groupsBy` and `groupsByRolling`
benchmark/Array.hs+3−2
@@ -13,6 +13,7 @@ import System.Random (randomRIO)
13import qualified GHC.Exts as GHC
13import qualified GHC.Exts as GHC
14
14
15import qualified ArrayOps as Ops
15import qualified ArrayOps as Ops
16+import qualified Streamly.Internal.Memory.Array as IA
16import qualified Streamly.Memory.Array as A
17import qualified Streamly.Memory.Array as A
17import qualified Streamly.Prelude as S
18import qualified Streamly.Prelude as S
18
19
@@ -87,8 +88,8 @@ main =
87 , benchPureSink "min" Ops.ordInstanceMin
88 , benchPureSink "min" Ops.ordInstanceMin
88 , benchPureSink "IsList.toList" GHC.toList
89 , benchPureSink "IsList.toList" GHC.toList
89 , benchIOSink "foldl'" Ops.pureFoldl'
90 , benchIOSink "foldl'" Ops.pureFoldl'
90− , benchIOSink "read" (S.drain . A.read)
91+ , benchIOSink "read" (S.drain . S.unfold A.read)
91− , benchIOSink "readRev" (S.drain . A.readRev)
92+ , benchIOSink "toStreamRev" (S.drain . IA.toStreamRev)
92#ifdef DEVBUILD
93#ifdef DEVBUILD
93 , benchPureSink "foldable/foldl'" Ops.foldableFoldl'
94 , benchPureSink "foldable/foldl'" Ops.foldableFoldl'
94 , benchPureSink "foldable/sum" Ops.foldableSum
95 , benchPureSink "foldable/sum" Ops.foldableSum
benchmark/ArrayOps.hs+2−2
@@ -280,7 +280,7 @@ onArray
280 :: MonadIO m => (S.SerialT m Int -> S.SerialT m Int)
280 :: MonadIO m => (S.SerialT m Int -> S.SerialT m Int)
281 -> Stream Int
281 -> Stream Int
282 -> m (Stream Int)
282 -> m (Stream Int)
283−onArray f arr = S.fold (A.writeN value) $ f $ A.read arr
283+onArray f arr = S.fold (A.writeN value) $ f $ (S.unfold A.read arr)
284
284
285scanl' n = composeN n $ onArray $ S.scanl' (+) 0
285scanl' n = composeN n $ onArray $ S.scanl' (+) 0
286scanl1' n = composeN n $ onArray $ S.scanl1' (+)
286scanl1' n = composeN n $ onArray $ S.scanl1' (+)
@@ -511,7 +511,7 @@ readInstance str =
511
511
512{-# INLINE pureFoldl' #-}
512{-# INLINE pureFoldl' #-}
513pureFoldl' :: MonadIO m => Stream Int -> m Int
513pureFoldl' :: MonadIO m => Stream Int -> m Int
514−pureFoldl' = S.foldl' (+) 0 . A.read
514+pureFoldl' = S.foldl' (+) 0 . S.unfold A.read
515
515
516#ifdef DEVBUILD
516#ifdef DEVBUILD
517{-# INLINE foldableFoldl' #-}
517{-# INLINE foldableFoldl' #-}
examples/FileSinkServer.hs+1−1
@@ -23,7 +23,7 @@ main = do
23 withFile file AppendMode
23 withFile file AppendMode
24 (\src -> S.fold (FH.write src)
24 (\src -> S.fold (FH.write src)
25 $ encodeChar8Unchecked
25 $ encodeChar8Unchecked
26− $ S.concatMap A.read
26+ $ S.concatUnfold A.read
27 $ S.concatMapWith parallel (flip NS.withSocketS recv)
27 $ S.concatMapWith parallel (flip NS.withSocketS recv)
28 $ NS.connectionsOnAllAddrs 8090)
28 $ NS.connectionsOnAllAddrs 8090)
29
29
examples/WordClassifier.hs+4−3
@@ -19,16 +19,17 @@ import Foreign.Storable (Storable(..))
19import qualified Streamly.Data.String as Streamly
19import qualified Streamly.Data.String as Streamly
20import qualified Streamly.FileSystem.Handle as FH
20import qualified Streamly.FileSystem.Handle as FH
21import qualified Streamly.Data.Fold as FL
21import qualified Streamly.Data.Fold as FL
22−import qualified Streamly.Internal.Data.Fold as Internal
22+import qualified Streamly.Internal.Data.Fold as IFL
23+import qualified Streamly.Internal.Data.Unfold as IUF
23import qualified Streamly.Memory.Array as A
24import qualified Streamly.Memory.Array as A
24import qualified Streamly.Prelude as Streamly
25import qualified Streamly.Prelude as Streamly
25import System.Environment (getArgs)
26import System.Environment (getArgs)
26import System.IO (openFile, IOMode(..))
27import System.IO (openFile, IOMode(..))
27
28
28instance (Enum a, Storable a) => Hashable (A.Array a) where
29instance (Enum a, Storable a) => Hashable (A.Array a) where
29− hash arr = runIdentity $ Streamly.fold Internal.rollingHash (A.read arr)
30+ hash arr = runIdentity $ IUF.fold A.read IFL.rollingHash arr
30 hashWithSalt salt arr = runIdentity $
31 hashWithSalt salt arr = runIdentity $
31− Streamly.fold (Internal.rollingHashWithSalt salt) (A.read arr)
32+ IUF.fold A.read (IFL.rollingHashWithSalt salt) arr
32
33
33{-# INLINE toLower #-}
34{-# INLINE toLower #-}
34toLower :: Char -> Char
35toLower :: Char -> Char
src/Streamly/Benchmark/FileIO/Array.hs+2−1
@@ -44,6 +44,7 @@ import qualified Streamly.Memory.Array as A
44import qualified Streamly.Prelude as S
44import qualified Streamly.Prelude as S
45import qualified Streamly.Data.String as SS
45import qualified Streamly.Data.String as SS
46import qualified Streamly.Internal.Prelude as Internal
46import qualified Streamly.Internal.Prelude as Internal
47+import qualified Streamly.Internal.Memory.Array as IA
47import qualified Streamly.Internal.Memory.ArrayStream as AS
48import qualified Streamly.Internal.Memory.ArrayStream as AS
48
49
49#ifdef INSPECTION
50#ifdef INSPECTION
@@ -104,7 +105,7 @@ inspect $ 'countWords `hasNoType` ''Step
104{-# INLINE sumBytes #-}
105{-# INLINE sumBytes #-}
105sumBytes :: Handle -> IO Word8
106sumBytes :: Handle -> IO Word8
106sumBytes inh = do
107sumBytes inh = do
107− let foldlArr' f z = runIdentity . S.foldl' f z . A.read
108+ let foldlArr' f z = runIdentity . S.foldl' f z . IA.toStream
108 let s = FH.readArrays inh
109 let s = FH.readArrays inh
109 S.foldl' (\acc arr -> acc + foldlArr' (+) 0 arr) 0 s
110 S.foldl' (\acc arr -> acc + foldlArr' (+) 0 arr) 0 s
110
111
src/Streamly/Benchmark/FileIO/Stream.hs+3−3
@@ -135,7 +135,7 @@ countLinesU inh =
135 S.length
135 S.length
136 $ SS.foldLines FL.drain
136 $ SS.foldLines FL.drain
137 $ SS.decodeChar8
137 $ SS.decodeChar8
138− $ IP.concatMapU AT.readU (FH.readArrays inh)
138+ $ S.concatUnfold A.read (FH.readArrays inh)
139
139
140#ifdef INSPECTION
140#ifdef INSPECTION
141inspect $ hasNoTypeClasses 'countLinesU
141inspect $ hasNoTypeClasses 'countLinesU
@@ -344,7 +344,7 @@ isSp = isSpace . chr . fromIntegral
344wordsUnwordsCopyWord8 :: Handle -> Handle -> IO ()
344wordsUnwordsCopyWord8 :: Handle -> Handle -> IO ()
345wordsUnwordsCopyWord8 inh outh =
345wordsUnwordsCopyWord8 inh outh =
346 S.fold (FH.write outh)
346 S.fold (FH.write outh)
347− $ IP.concatMapU IUF.fromList
347+ $ S.concatUnfold IUF.fromList
348 $ S.intersperse [32]
348 $ S.intersperse [32]
349 $ S.wordsBy isSp FL.toList
349 $ S.wordsBy isSp FL.toList
350 $ FH.read inh
350 $ FH.read inh
@@ -361,7 +361,7 @@ wordsUnwordsCopy :: Handle -> Handle -> IO ()
361wordsUnwordsCopy inh outh =
361wordsUnwordsCopy inh outh =
362 S.fold (FH.write outh)
362 S.fold (FH.write outh)
363 $ SS.encodeChar8
363 $ SS.encodeChar8
364− $ IP.concatMapU IUF.fromList
364+ $ S.concatUnfold IUF.fromList
365 $ S.intersperse " "
365 $ S.intersperse " "
366 -- Array allocation is too expensive for such small strings. So just use
366 -- Array allocation is too expensive for such small strings. So just use
367 -- lists instead.
367 -- lists instead.
src/Streamly/Benchmark/Prelude.hs+1−1
@@ -720,7 +720,7 @@ inspect $ hasNoTypeClasses 'concatMapRepl4xN
720{-# INLINE concatUnfoldRepl4xN #-}
720{-# INLINE concatUnfoldRepl4xN #-}
721concatUnfoldRepl4xN :: Int -> IO ()
721concatUnfoldRepl4xN :: Int -> IO ()
722concatUnfoldRepl4xN n =
722concatUnfoldRepl4xN n =
723− S.drain $ Internal.concatMapU
723+ S.drain $ S.concatUnfold
724 (UF.replicateM 4)
724 (UF.replicateM 4)
725 (sourceUnfoldrMN (value `div` 4) n)
725 (sourceUnfoldrMN (value `div` 4) n)
726
726
src/Streamly/Data/String.hs+2−3
@@ -95,7 +95,6 @@ import Streamly.Internal.Data.Unfold (Unfold)
95
95
96import qualified Streamly.Internal.Prelude as S
96import qualified Streamly.Internal.Prelude as S
97import qualified Streamly.Memory.Array as A
97import qualified Streamly.Memory.Array as A
98−import qualified Streamly.Internal.Memory.Array.Types as A
99import qualified Streamly.Internal.Memory.ArrayStream as AS
98import qualified Streamly.Internal.Memory.ArrayStream as AS
100import qualified Streamly.Streams.StreamD as D
99import qualified Streamly.Streams.StreamD as D
101import qualified Streamly.Internal.Data.Unfold as UF
100import qualified Streamly.Internal.Data.Unfold as UF
@@ -284,14 +283,14 @@ unfoldLines unf = S.intercalateSuffix UF.singleton '\n' unf
284-- >>> S.toList $ unlines $ S.fromList ["lines", "this", "string"]
283-- >>> S.toList $ unlines $ S.fromList ["lines", "this", "string"]
285-- "lines\nthis\nstring\n"
284-- "lines\nthis\nstring\n"
286--
285--
287−-- > unlines = unfoldLines A.readU
286+-- > unlines = unfoldLines A.read
288--
287--
289-- Note that, in general
288-- Note that, in general
290--
289--
291-- > unlines . lines /= id
290-- > unlines . lines /= id
292{-# INLINE unlines #-}
291{-# INLINE unlines #-}
293unlines :: (MonadIO m, IsStream t) => t m (Array Char) -> t m Char
292unlines :: (MonadIO m, IsStream t) => t m (Array Char) -> t m Char
294−unlines = unfoldLines A.readU
293+unlines = unfoldLines A.read
295
294
296-- | Flattens the stream of @Array Char@, after appending a separating
295-- | Flattens the stream of @Array Char@, after appending a separating
297-- space to each string.
296-- space to each string.
src/Streamly/Internal/Memory/Array.hs+58−11
@@ -64,8 +64,9 @@ module Streamly.Internal.Memory.Array
64 -- list.
64 -- list.
65
65
66 , A.toList
66 , A.toList
67+ , toStream
68+ , toStreamRev
67− , A.read
69+ , read
68− , readRev
69
70
70 -- * Random Access
71 -- * Random Access
71 , length
72 , length
@@ -96,19 +97,25 @@ where
96
97
97import Control.Monad.IO.Class (MonadIO(..))
98import Control.Monad.IO.Class (MonadIO(..))
98-- import Data.Functor.Identity (Identity)
99-- import Data.Functor.Identity (Identity)
99−import Foreign.ForeignPtr (withForeignPtr)
100+import Foreign.ForeignPtr (withForeignPtr, touchForeignPtr)
101+import Foreign.Ptr (plusPtr)
100import Foreign.Storable (Storable(..))
102import Foreign.Storable (Storable(..))
101import Prelude hiding (length, null, last, map, (!!), read, concat)
103import Prelude hiding (length, null, last, map, (!!), read, concat)
102
104
105+import GHC.ForeignPtr (ForeignPtr(..))
106+import GHC.Ptr (Ptr(..))
107+
108+import Streamly.Internal.Data.Fold.Types (Fold(..))
109+import Streamly.Internal.Data.Unfold.Types (Unfold(..))
103import Streamly.Internal.Memory.Array.Types (Array(..), length)
110import Streamly.Internal.Memory.Array.Types (Array(..), length)
104import Streamly.Streams.Serial (SerialT)
111import Streamly.Streams.Serial (SerialT)
105import Streamly.Streams.StreamK.Type (IsStream)
112import Streamly.Streams.StreamK.Type (IsStream)
106−import Streamly.Internal.Data.Fold.Types (Fold(..))
107
113
108import qualified Streamly.Internal.Memory.Array.Types as A
114import qualified Streamly.Internal.Memory.Array.Types as A
109import qualified Streamly.Streams.Prelude as P
115import qualified Streamly.Streams.Prelude as P
110import qualified Streamly.Streams.Serial as Serial
116import qualified Streamly.Streams.Serial as Serial
111import qualified Streamly.Streams.StreamD as D
117import qualified Streamly.Streams.StreamD as D
118+import qualified Streamly.Streams.StreamK as K
112
119
113-------------------------------------------------------------------------------
120-------------------------------------------------------------------------------
114-- Construction
121-- Construction
@@ -151,16 +158,56 @@ fromStream = P.runFold A.write
151-- Elimination
158-- Elimination
152-------------------------------------------------------------------------------
159-------------------------------------------------------------------------------
153
160
161+-- | Convert an 'Array' into a stream.
162+--
163+-- /Internal/
164+{-# INLINE_EARLY toStream #-}
165+toStream :: (Monad m, K.IsStream t, Storable a) => Array a -> t m a
166+toStream = D.fromStreamD . A.toStreamD
167+-- XXX add fallback to StreamK rule
168+-- {-# RULES "Streamly.Array.read fallback to StreamK" [1]
169+-- forall a. S.readK (read a) = K.fromArray a #-}
170+
154-- | Convert an 'Array' into a stream in reverse order.
171-- | Convert an 'Array' into a stream in reverse order.
155--
172--
156−-- @since 0.7.0
173+-- /Internal/
157−{-# INLINE_EARLY readRev #-}
174+{-# INLINE_EARLY toStreamRev #-}
158−readRev :: (Monad m, IsStream t, Storable a) => Array a -> t m a
175+toStreamRev :: (Monad m, IsStream t, Storable a) => Array a -> t m a
159−readRev = D.fromStreamD . A.toStreamDRev
176+toStreamRev = D.fromStreamD . A.toStreamDRev
160-- XXX add fallback to StreamK rule
177-- XXX add fallback to StreamK rule
161-- {-# RULES "Streamly.Array.readRev fallback to StreamK" [1]
178-- {-# RULES "Streamly.Array.readRev fallback to StreamK" [1]
162-- forall a. S.toStreamK (readRev a) = K.revFromArray a #-}
179-- forall a. S.toStreamK (readRev a) = K.revFromArray a #-}
163
180
181+data ReadUState a = ReadUState
182+ {-# UNPACK #-} !(ForeignPtr a) -- foreign ptr with end of array pointer
183+ {-# UNPACK #-} !(Ptr a) -- current pointer
184+
185+-- | Unfold an array into a stream.
186+--
187+-- @since 0.7.0
188+{-# INLINE_NORMAL read #-}
189+read :: forall m a. (Monad m, Storable a) => Unfold m (Array a) a
190+read = Unfold step inject
191+ where
192+
193+ inject (Array (ForeignPtr start contents) (Ptr end) _) =
194+ return $ ReadUState (ForeignPtr end contents) (Ptr start)
195+
196+ {-# INLINE_LATE step #-}
197+ step (ReadUState fp@(ForeignPtr end _) p) | p == (Ptr end) =
198+ let x = A.unsafeInlineIO $ touchForeignPtr fp
199+ in x `seq` return D.Stop
200+ step (ReadUState fp p) = do
201+ -- unsafeInlineIO allows us to run this in Identity monad for pure
202+ -- toList/foldr case which makes them much faster due to not
203+ -- accumulating the list and fusing better with the pure consumers.
204+ --
205+ -- This should be safe as the array contents are guaranteed to be
206+ -- evaluated/written to before we peek at them.
207+ let !x = A.unsafeInlineIO $ peek p
208+ return $ D.Yield x
209+ (ReadUState fp (p `plusPtr` (sizeOf (undefined :: a))))
210+
164-- | > null arr = length arr == 0
211-- | > null arr = length arr == 0
165--
212--
166-- /Internal/
213-- /Internal/
@@ -375,18 +422,18 @@ streamTransform :: forall m a b. (MonadIO m, Storable a, Storable b)
375 => (SerialT m a -> SerialT m b) -> Array a -> m (Array b)
422 => (SerialT m a -> SerialT m b) -> Array a -> m (Array b)
376streamTransform f arr =
423streamTransform f arr =
377 P.runFold (A.toArrayMinChunk (alignment (undefined :: a)) (length arr))
424 P.runFold (A.toArrayMinChunk (alignment (undefined :: a)) (length arr))
378− $ f (A.read arr)
425+ $ f (toStream arr)
379
426
380-- | Fold an array using a 'Fold'.
427-- | Fold an array using a 'Fold'.
381--
428--
382-- /Internal/
429-- /Internal/
383{-# INLINE fold #-}
430{-# INLINE fold #-}
384fold :: forall m a b. (MonadIO m, Storable a) => Fold m a b -> Array a -> m b
431fold :: forall m a b. (MonadIO m, Storable a) => Fold m a b -> Array a -> m b
385−fold f arr = P.runFold f $ (A.read arr :: Serial.SerialT m a)
432+fold f arr = P.runFold f $ (toStream arr :: Serial.SerialT m a)
386
433
387-- | Fold an array using a stream fold operation.
434-- | Fold an array using a stream fold operation.
388--
435--
389-- /Internal/
436-- /Internal/
390{-# INLINE streamFold #-}
437{-# INLINE streamFold #-}
391streamFold :: (MonadIO m, Storable a) => (SerialT m a -> m b) -> Array a -> m b
438streamFold :: (MonadIO m, Storable a) => (SerialT m a -> m b) -> Array a -> m b
392−streamFold f arr = f (A.read arr)
439+streamFold f arr = f (toStream arr)
src/Streamly/Internal/Memory/Array/Types.hs−40
@@ -68,8 +68,6 @@ module Streamly.Internal.Memory.Array.Types
68 , writeNUnsafe
68 , writeNUnsafe
69 , write
69 , write
70 , writeAligned
70 , writeAligned
71− , read
72− , readU
73
71
74 -- * Utilities
72 -- * Utilities
75 , defaultChunkSize
73 , defaultChunkSize
@@ -111,7 +109,6 @@ import GHC.IO (IO(IO), unsafePerformIO)
111import GHC.Ptr (Ptr(..))
109import GHC.Ptr (Ptr(..))
112
110
113import Streamly.Internal.Data.Fold.Types (Fold(..))
111import Streamly.Internal.Data.Fold.Types (Fold(..))
114−import Streamly.Internal.Data.Unfold.Types (Unfold(..))
115import Streamly.Internal.Data.Strict (Tuple'(..))
112import Streamly.Internal.Data.Strict (Tuple'(..))
116import Streamly.Internal.Data.SVar (adaptState)
113import Streamly.Internal.Data.SVar (adaptState)
117
114
@@ -407,33 +404,6 @@ byteCapacity Array{..} =
407 len = aBound `minusPtr` p
404 len = aBound `minusPtr` p
408 in assert (len >= 0) len
405 in assert (len >= 0) len
409
406
410−data ReadUState a = ReadUState
411− {-# UNPACK #-} !(ForeignPtr a) -- foreign ptr with end of array pointer
412− {-# UNPACK #-} !(Ptr a) -- current pointer
413−
414−{-# INLINE_NORMAL readU #-}
415−readU :: forall m a. (Monad m, Storable a) => Unfold m (Array a) a
416−readU = Unfold step inject
417− where
418−
419− inject (Array (ForeignPtr start contents) (Ptr end) _) =
420− return $ ReadUState (ForeignPtr end contents) (Ptr start)
421−
422− {-# INLINE_LATE step #-}
423− step (ReadUState fp@(ForeignPtr end _) p) | p == (Ptr end) =
424− let x = unsafeInlineIO $ touchForeignPtr fp
425− in x `seq` return D.Stop
426− step (ReadUState fp p) = do
427− -- unsafeInlineIO allows us to run this in Identity monad for pure
428− -- toList/foldr case which makes them much faster due to not
429− -- accumulating the list and fusing better with the pure consumers.
430− --
431− -- This should be safe as the array contents are guaranteed to be
432− -- evaluated/written to before we peek at them.
433− let !x = unsafeInlineIO $ peek p
434− return $ D.Yield x
435− (ReadUState fp (p `plusPtr` (sizeOf (undefined :: a))))
436−
437{-# INLINE_NORMAL toStreamD #-}
407{-# INLINE_NORMAL toStreamD #-}
438toStreamD :: forall m a. (Monad m, Storable a) => Array a -> D.Stream m a
408toStreamD :: forall m a. (Monad m, Storable a) => Array a -> D.Stream m a
439toStreamD Array{..} =
409toStreamD Array{..} =
@@ -905,16 +875,6 @@ instance Foldable Array where
905 foldr = _foldr
875 foldr = _foldr
906#endif
876#endif
907
877
908−-- | Convert an 'Array' into a stream.
909−--
910−-- @since 0.7.0
911−{-# INLINE_EARLY read #-}
912−read :: (Monad m, K.IsStream t, Storable a) => Array a -> t m a
913−read = D.fromStreamD . toStreamD
914−-- XXX add fallback to StreamK rule
915−-- {-# RULES "Streamly.Array.read fallback to StreamK" [1]
916−-- forall a. S.readK (read a) = K.fromArray a #-}
917−
918-------------------------------------------------------------------------------
878-------------------------------------------------------------------------------
919-- Semigroup and Monoid
879-- Semigroup and Monoid
920-------------------------------------------------------------------------------
880-------------------------------------------------------------------------------
src/Streamly/Internal/Memory/ArrayStream.hs+4−3
@@ -52,6 +52,7 @@ import Streamly.Streams.Serial (SerialT)
52import Streamly.Streams.StreamK.Type (IsStream)
52import Streamly.Streams.StreamK.Type (IsStream)
53
53
54import qualified Streamly.Internal.Data.Unfold as UF
54import qualified Streamly.Internal.Data.Unfold as UF
55+import qualified Streamly.Internal.Memory.Array as A
55import qualified Streamly.Internal.Memory.Array.Types as A
56import qualified Streamly.Internal.Memory.Array.Types as A
56import qualified Streamly.Internal.Prelude as S
57import qualified Streamly.Internal.Prelude as S
57import qualified Streamly.Streams.StreamD as D
58import qualified Streamly.Streams.StreamD as D
@@ -72,7 +73,7 @@ import qualified Streamly.Streams.Prelude as P
72concat :: (IsStream t, MonadIO m, Storable a) => t m (Array a) -> t m a
73concat :: (IsStream t, MonadIO m, Storable a) => t m (Array a) -> t m a
73-- concat m = D.fromStreamD $ A.flattenArrays (D.toStreamD m)
74-- concat m = D.fromStreamD $ A.flattenArrays (D.toStreamD m)
74-- concat m = D.fromStreamD $ D.concatMap A.toStreamD (D.toStreamD m)
75-- concat m = D.fromStreamD $ D.concatMap A.toStreamD (D.toStreamD m)
75−concat m = D.fromStreamD $ D.concatMapU A.readU (D.toStreamD m)
76+concat m = D.fromStreamD $ D.concatMapU A.read (D.toStreamD m)
76
77
77-- XXX should we have a reverseArrays API to reverse the stream of arrays
78-- XXX should we have a reverseArrays API to reverse the stream of arrays
78-- instead?
79-- instead?
@@ -88,7 +89,7 @@ concatRev m = D.fromStreamD $ A.flattenArraysRev (D.toStreamD m)
88{-# INLINE intercalateSuffix #-}
89{-# INLINE intercalateSuffix #-}
89intercalateSuffix :: (MonadIO m, IsStream t, Storable a)
90intercalateSuffix :: (MonadIO m, IsStream t, Storable a)
90 => Array a -> t m (Array a) -> t m a
91 => Array a -> t m (Array a) -> t m a
91−intercalateSuffix arr = S.intercalateSuffix A.readU arr A.readU
92+intercalateSuffix arr = S.intercalateSuffix A.read arr A.read
92
93
93-- | Flatten a stream of arrays appending the given element after each
94-- | Flatten a stream of arrays appending the given element after each
94-- array.
95-- array.
@@ -98,7 +99,7 @@ intercalateSuffix arr = S.intercalateSuffix A.readU arr A.readU
98interposeSuffix :: (MonadIO m, IsStream t, Storable a)
99interposeSuffix :: (MonadIO m, IsStream t, Storable a)
99 => a -> t m (Array a) -> t m a
100 => a -> t m (Array a) -> t m a
100-- interposeSuffix x = D.fromStreamD . A.unlines x . D.toStreamD
101-- interposeSuffix x = D.fromStreamD . A.unlines x . D.toStreamD
101−interposeSuffix x = S.intercalateSuffix UF.singleton x A.readU
102+interposeSuffix x = S.intercalateSuffix UF.singleton x A.read
102
103
103-- | Split a stream of arrays on a given separator byte, dropping the separator
104-- | Split a stream of arrays on a given separator byte, dropping the separator
104-- and coalescing all the arrays between two separators into a single array.
105-- and coalescing all the arrays between two separators into a single array.
src/Streamly/Internal/Prelude.hs+8−7
@@ -248,7 +248,7 @@ module Streamly.Internal.Prelude
248
248
249 -- ** Nested Streams
249 -- ** Nested Streams
250 , concatMapM
250 , concatMapM
251− , concatMapU
251+ , concatUnfold
252 , concatUnfoldInterleave
252 , concatUnfoldInterleave
253 , concatUnfoldRoundrobin
253 , concatUnfoldRoundrobin
254 , concatMap
254 , concatMap
@@ -426,7 +426,7 @@ import Streamly.Internal.Data.Time.Units
426
426
427import Streamly.Internal.Data.Strict
427import Streamly.Internal.Data.Strict
428
428
429−import qualified Streamly.Internal.Memory.Array.Types as A
429+import qualified Streamly.Internal.Memory.Array as A
430import qualified Streamly.Data.Fold as FL
430import qualified Streamly.Data.Fold as FL
431import qualified Streamly.Internal.Data.Fold.Types as FL
431import qualified Streamly.Internal.Data.Fold.Types as FL
432import qualified Streamly.Streams.Prelude as P
432import qualified Streamly.Streams.Prelude as P
@@ -542,7 +542,7 @@ unfoldrMSerial step seed = fromStreamS (S.unfoldrM step seed)
542--
542--
543-- >>> unfold UF.replicateM 10 (putStrLn "hello")
543-- >>> unfold UF.replicateM 10 (putStrLn "hello")
544--
544--
545−-- /Internal/
545+-- /Since: 0.7.0/
546{-# INLINE unfold #-}
546{-# INLINE unfold #-}
547unfold :: (IsStream t, Monad m) => Unfold m a b -> a -> t m b
547unfold :: (IsStream t, Monad m) => Unfold m a b -> a -> t m b
548unfold unf x = fromStreamD $ D.unfold unf x
548unfold unf x = fromStreamD $ D.unfold unf x
@@ -2210,9 +2210,9 @@ concatMapM f m = fromStreamD $ D.concatMapM (fmap toStreamD . f) (toStreamD m)
2210-- therefore provide many times better performance.
2210-- therefore provide many times better performance.
2211--
2211--
2212-- @since 0.7.0
2212-- @since 0.7.0
2213−{-# INLINE concatMapU #-}
2213+{-# INLINE concatUnfold #-}
2214−concatMapU ::(IsStream t, Monad m) => Unfold m a b -> t m a -> t m b
2214+concatUnfold ::(IsStream t, Monad m) => Unfold m a b -> t m a -> t m b
2215−concatMapU u m = fromStreamD $ D.concatMapU u (toStreamD m)
2215+concatUnfold u m = fromStreamD $ D.concatMapU u (toStreamD m)
2216
2216
2217-- | Like 'concatUnfold' but interleaves the streams in the same way as
2217-- | Like 'concatUnfold' but interleaves the streams in the same way as
2218-- 'interleave' behaves instead of appending them.
2218-- 'interleave' behaves instead of appending them.
@@ -2988,7 +2988,8 @@ wordsOn subseq f m = undefined -- D.fromStreamD $ D.wordsOn f subseq (D.toStream
2988splitBySeq
2988splitBySeq
2989 :: (IsStream t, MonadAsync m, Storable a, Enum a, Eq a)
2989 :: (IsStream t, MonadAsync m, Storable a, Enum a, Eq a)
2990 => Array a -> Fold m a b -> t m a -> t m b
2990 => Array a -> Fold m a b -> t m a -> t m b
2991+splitBySeq patt f m =
2991−splitBySeq patt f m = intersperseM (fold f (A.read patt)) $ splitOnSeq patt f m
2992+ intersperseM (fold f (A.toStream patt)) $ splitOnSeq patt f m
2992
2993
2993-- | Like 'splitSuffixOn' but keeps the suffix intact in the splits.
2994-- | Like 'splitSuffixOn' but keeps the suffix intact in the splits.
2994--
2995--
src/Streamly/Memory/Array.hs−1
@@ -90,7 +90,6 @@ module Streamly.Memory.Array
90
90
91 , A.toList
91 , A.toList
92 , A.read
92 , A.read
93− , readRev
94
93
95 -- ** Random Access
94 -- ** Random Access
96 , A.length
95 , A.length
src/Streamly/Prelude.hs+2
@@ -92,6 +92,7 @@ module Streamly.Prelude
92 -- | Generate a monadic stream from a seed value and a generator function.
92 -- | Generate a monadic stream from a seed value and a generator function.
93 , unfoldr
93 , unfoldr
94 , unfoldrM
94 , unfoldrM
95+ , unfold
95 , iterate
96 , iterate
96 , iterateM
97 , iterateM
97 , fromIndices
98 , fromIndices
@@ -662,6 +663,7 @@ module Streamly.Prelude
662 --, bindWith
663 --, bindWith
663 , concatMap
664 , concatMap
664 , concatMapM
665 , concatMapM
666+ , concatUnfold
665
667
666 -- * Exceptions
668 -- * Exceptions
667 , before
669 , before
test/Arrays.hs+7−7
@@ -11,8 +11,8 @@ import Test.QuickCheck.Monadic (monadicIO, assert)
11
11
12import Test.Hspec as H
12import Test.Hspec as H
13
13
14+import qualified Streamly.Internal.Memory.Array as IA
14import qualified Streamly.Memory.Array as A
15import qualified Streamly.Memory.Array as A
15−import qualified Streamly.Internal.Memory.Array.Types as AT
16import qualified Streamly.Prelude as S
16import qualified Streamly.Prelude as S
17import qualified Streamly.Internal.Prelude as IP
17import qualified Streamly.Internal.Prelude as IP
18
18
@@ -55,7 +55,7 @@ testFromToStreamN =
55 arr <- S.fold (A.writeN len)
55 arr <- S.fold (A.writeN len)
56 $ S.fromList list
56 $ S.fromList list
57 xs <- S.toList
57 xs <- S.toList
58− $ A.read arr
58+ $ S.unfold A.read arr
59 assert (xs == list)
59 assert (xs == list)
60
60
61testToStreamRev :: Property
61testToStreamRev :: Property
@@ -66,7 +66,7 @@ testToStreamRev =
66 arr <- S.fold (A.writeN len)
66 arr <- S.fold (A.writeN len)
67 $ S.fromList list
67 $ S.fromList list
68 xs <- S.toList
68 xs <- S.toList
69− $ A.readRev arr
69+ $ IA.toStreamRev arr
70 assert (xs == reverse list)
70 assert (xs == reverse list)
71
71
72testArraysOf :: Property
72testArraysOf :: Property
@@ -75,7 +75,7 @@ testArraysOf =
75 forAll (vectorOf len (arbitrary :: Gen Int)) $ \list ->
75 forAll (vectorOf len (arbitrary :: Gen Int)) $ \list ->
76 monadicIO $ do
76 monadicIO $ do
77 xs <- S.toList
77 xs <- S.toList
78− $ S.concatMap A.read
78+ $ S.concatUnfold A.read
79 $ IP.arraysOf 240
79 $ IP.arraysOf 240
80 $ S.fromList list
80 $ S.fromList list
81 assert (xs == list)
81 assert (xs == list)
@@ -86,7 +86,7 @@ testFlattenArrays =
86 forAll (vectorOf len (arbitrary :: Gen Int)) $ \list ->
86 forAll (vectorOf len (arbitrary :: Gen Int)) $ \list ->
87 monadicIO $ do
87 monadicIO $ do
88 xs <- S.toList
88 xs <- S.toList
89− $ IP.concatMapU AT.readU
89+ $ S.concatUnfold A.read
90 $ IP.arraysOf 240
90 $ IP.arraysOf 240
91 $ S.fromList list
91 $ S.fromList list
92 assert (xs == list)
92 assert (xs == list)
@@ -98,7 +98,7 @@ testFromToStream =
98 monadicIO $ do
98 monadicIO $ do
99 arr <- S.fold A.write $ S.fromList list
99 arr <- S.fold A.write $ S.fromList list
100 xs <- S.toList
100 xs <- S.toList
101− $ A.read arr
101+ $ S.unfold A.read arr
102 assert (xs == list)
102 assert (xs == list)
103
103
104main :: IO ()
104main :: IO ()
@@ -109,7 +109,7 @@ main = hspec
109 describe "Construction" $ do
109 describe "Construction" $ do
110 prop "length . writeN n === n" $ testLength
110 prop "length . writeN n === n" $ testLength
111 prop "read . writeN n === id" $ testFromToStreamN
111 prop "read . writeN n === id" $ testFromToStreamN
112− prop "readRev . write === reverse" $ testToStreamRev
112+ prop "toStreamRev . write === reverse" $ testToStreamRev
113 prop "arraysOf concats to original" $ testArraysOf
113 prop "arraysOf concats to original" $ testArraysOf
114 prop "concats to original" $ testFlattenArrays
114 prop "concats to original" $ testFlattenArrays
115 prop "read . write === id" $ testFromToStream
115 prop "read . write === id" $ testFromToStream