mirror of
https://github.com/composewell/streamly.git
synced 2024-09-11 11:37:22 +03:00
Rename concatUnfold to unfoldMany #986
This commit is contained in:
parent
7759cc0082
commit
b73b5ffa3a
@ -402,20 +402,20 @@ inspect $ hasNoTypeClasses 'concatMapRepl
|
||||
inspect $ 'concatMapRepl `hasNoType` ''SPEC
|
||||
#endif
|
||||
|
||||
-- concatUnfold replicate/unfoldrM
|
||||
-- unfoldMany replicate/unfoldrM
|
||||
|
||||
{-# INLINE concatUnfoldRepl #-}
|
||||
concatUnfoldRepl :: Int -> Int -> Int -> IO ()
|
||||
concatUnfoldRepl outer inner n =
|
||||
{-# INLINE unfoldManyRepl #-}
|
||||
unfoldManyRepl :: Int -> Int -> Int -> IO ()
|
||||
unfoldManyRepl outer inner n =
|
||||
S.drain
|
||||
$ S.concatUnfold
|
||||
$ S.unfoldMany
|
||||
(UF.lmap return (UF.replicateM inner))
|
||||
(sourceUnfoldrMN outer n)
|
||||
|
||||
#ifdef INSPECTION
|
||||
inspect $ hasNoTypeClasses 'concatUnfoldRepl
|
||||
inspect $ 'concatUnfoldRepl `hasNoType` ''S.ConcatMapUState
|
||||
inspect $ 'concatUnfoldRepl `hasNoType` ''SPEC
|
||||
inspect $ hasNoTypeClasses 'unfoldManyRepl
|
||||
inspect $ 'unfoldManyRepl `hasNoType` ''S.ConcatMapUState
|
||||
inspect $ 'unfoldManyRepl `hasNoType` ''SPEC
|
||||
#endif
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
@ -488,11 +488,11 @@ o_1_space =
|
||||
, benchIOSrc1 "concatMap (1 of n)"
|
||||
(concatMap 1 value)
|
||||
|
||||
-- concatMap vs concatUnfold
|
||||
-- concatMap vs unfoldMany
|
||||
, benchIOSrc1 "concatMapRepl (sqrt n of sqrt n)"
|
||||
(concatMapRepl value2 value2)
|
||||
, benchIOSrc1 "concatUnfoldRepl (sqrt n of sqrt n)"
|
||||
(concatUnfoldRepl value2 value2)
|
||||
, benchIOSrc1 "unfoldManyRepl (sqrt n of sqrt n)"
|
||||
(unfoldManyRepl value2 value2)
|
||||
]
|
||||
, bgroup "filtering"
|
||||
[ benchFold "filter-even" (filterEven 1) sourceUnfoldrM
|
||||
|
@ -286,7 +286,7 @@ toChunksConcatUnfoldCountLines inh =
|
||||
$ IUS.lines FL.drain
|
||||
$ SS.decodeLatin1
|
||||
-- XXX replace with toBytes
|
||||
$ S.concatUnfold A.read (IFH.toChunks inh)
|
||||
$ S.unfoldMany A.read (IFH.toChunks inh)
|
||||
|
||||
#ifdef INSPECTION
|
||||
inspect $ hasNoTypeClasses 'toChunksConcatUnfoldCountLines
|
||||
|
@ -261,22 +261,22 @@ inspect $ hasNoTypeClasses 'concatMapWithAppend
|
||||
inspect $ 'concatMapWithAppend `hasNoType` ''SPEC
|
||||
#endif
|
||||
|
||||
-- concatUnfold
|
||||
-- unfoldMany
|
||||
|
||||
-- concatUnfold replicate/unfoldrM
|
||||
-- unfoldMany replicate/unfoldrM
|
||||
|
||||
{-# INLINE concatUnfoldRepl #-}
|
||||
concatUnfoldRepl :: Int -> Int -> Int -> IO ()
|
||||
concatUnfoldRepl outer inner n =
|
||||
{-# INLINE unfoldManyRepl #-}
|
||||
unfoldManyRepl :: Int -> Int -> Int -> IO ()
|
||||
unfoldManyRepl outer inner n =
|
||||
S.drain
|
||||
$ S.concatUnfold
|
||||
$ S.unfoldMany
|
||||
(UF.lmap return (UF.replicateM inner))
|
||||
(sourceUnfoldrM outer n)
|
||||
|
||||
#ifdef INSPECTION
|
||||
inspect $ hasNoTypeClasses 'concatUnfoldRepl
|
||||
inspect $ 'concatUnfoldRepl `hasNoType` ''D.ConcatMapUState
|
||||
inspect $ 'concatUnfoldRepl `hasNoType` ''SPEC
|
||||
inspect $ hasNoTypeClasses 'unfoldManyRepl
|
||||
inspect $ 'unfoldManyRepl `hasNoType` ''D.ConcatMapUState
|
||||
inspect $ 'unfoldManyRepl `hasNoType` ''SPEC
|
||||
#endif
|
||||
|
||||
o_1_space_concat :: Int -> [Benchmark]
|
||||
@ -322,11 +322,11 @@ o_1_space_concat value = sqrtVal `seq`
|
||||
, benchIOSrc1 "concatMapWithAppend (2 of n/2)"
|
||||
(concatMapWithAppend 2 (value `div` 2))
|
||||
|
||||
-- concatMap vs concatUnfold
|
||||
-- concatMap vs unfoldMany
|
||||
, benchIOSrc1 "concatMapRepl (sqrt n of sqrt n)"
|
||||
(concatMapRepl sqrtVal sqrtVal)
|
||||
, benchIOSrc1 "concatUnfoldRepl (sqrt n of sqrt n)"
|
||||
(concatUnfoldRepl sqrtVal sqrtVal)
|
||||
, benchIOSrc1 "unfoldManyRepl (sqrt n of sqrt n)"
|
||||
(unfoldManyRepl sqrtVal sqrtVal)
|
||||
]
|
||||
]
|
||||
|
||||
|
@ -122,31 +122,31 @@ o_1_space_concat value =
|
||||
]
|
||||
]
|
||||
|
||||
{-# INLINE concatUnfoldInterleaveRepl4xN #-}
|
||||
concatUnfoldInterleaveRepl4xN :: Int -> Int -> IO ()
|
||||
concatUnfoldInterleaveRepl4xN value n =
|
||||
S.drain $ Internal.concatUnfoldInterleave
|
||||
{-# INLINE unfoldManyInterleaveRepl4xN #-}
|
||||
unfoldManyInterleaveRepl4xN :: Int -> Int -> IO ()
|
||||
unfoldManyInterleaveRepl4xN value n =
|
||||
S.drain $ Internal.unfoldManyInterleave
|
||||
(UF.lmap return (UF.replicateM 4))
|
||||
(sourceUnfoldrM (value `div` 4) n)
|
||||
|
||||
#ifdef INSPECTION
|
||||
inspect $ hasNoTypeClasses 'concatUnfoldInterleaveRepl4xN
|
||||
-- inspect $ 'concatUnfoldInterleaveRepl4xN `hasNoType` ''SPEC
|
||||
-- inspect $ 'concatUnfoldInterleaveRepl4xN `hasNoType`
|
||||
inspect $ hasNoTypeClasses 'unfoldManyInterleaveRepl4xN
|
||||
-- inspect $ 'unfoldManyInterleaveRepl4xN `hasNoType` ''SPEC
|
||||
-- inspect $ 'unfoldManyInterleaveRepl4xN `hasNoType`
|
||||
-- ''D.ConcatUnfoldInterleaveState
|
||||
#endif
|
||||
|
||||
{-# INLINE concatUnfoldRoundrobinRepl4xN #-}
|
||||
concatUnfoldRoundrobinRepl4xN :: Int -> Int -> IO ()
|
||||
concatUnfoldRoundrobinRepl4xN value n =
|
||||
S.drain $ Internal.concatUnfoldRoundrobin
|
||||
{-# INLINE unfoldManyRoundRobinRepl4xN #-}
|
||||
unfoldManyRoundRobinRepl4xN :: Int -> Int -> IO ()
|
||||
unfoldManyRoundRobinRepl4xN value n =
|
||||
S.drain $ Internal.unfoldManyRoundRobin
|
||||
(UF.lmap return (UF.replicateM 4))
|
||||
(sourceUnfoldrM (value `div` 4) n)
|
||||
|
||||
#ifdef INSPECTION
|
||||
inspect $ hasNoTypeClasses 'concatUnfoldRoundrobinRepl4xN
|
||||
-- inspect $ 'concatUnfoldRoundrobinRepl4xN `hasNoType` ''SPEC
|
||||
-- inspect $ 'concatUnfoldRoundrobinRepl4xN `hasNoType`
|
||||
inspect $ hasNoTypeClasses 'unfoldManyRoundRobinRepl4xN
|
||||
-- inspect $ 'unfoldManyRoundRobinRepl4xN `hasNoType` ''SPEC
|
||||
-- inspect $ 'unfoldManyRoundRobinRepl4xN `hasNoType`
|
||||
-- ''D.ConcatUnfoldInterleaveState
|
||||
#endif
|
||||
|
||||
@ -159,11 +159,11 @@ o_n_heap_concat value =
|
||||
-- WSerial expands slowly because of binary interleave behavior and
|
||||
-- this expands immediately because of Nary interleave behavior.
|
||||
benchIOSrc1
|
||||
"concatUnfoldInterleaveRepl (x/4,4)"
|
||||
(concatUnfoldInterleaveRepl4xN value)
|
||||
"unfoldManyInterleaveRepl (x/4,4)"
|
||||
(unfoldManyInterleaveRepl4xN value)
|
||||
, benchIOSrc1
|
||||
"concatUnfoldRoundrobinRepl (x/4,4)"
|
||||
(concatUnfoldRoundrobinRepl4xN value)
|
||||
"unfoldManyRoundRobinRepl (x/4,4)"
|
||||
(unfoldManyRoundRobinRepl4xN value)
|
||||
]
|
||||
]
|
||||
|
||||
|
@ -52,7 +52,7 @@ The haddock documentation includes a note when an operation cannot fuse.
|
||||
### Unfolds
|
||||
|
||||
* Use unfolds especially when higher order operations are involved. For
|
||||
example, `concatUnfold` can fuse completely whereas `concatMap` would
|
||||
example, `unfoldMany` can fuse completely whereas `concatMap` would
|
||||
not fuse.
|
||||
* Use `outerProduct` in `Unfold` module instead of using the monad instance of
|
||||
streams to fuse nested loops where performance matters. See the unfold
|
||||
|
@ -167,7 +167,7 @@ we can resolve this using fusion-plugin in future.
|
||||
### Delayed INLINE
|
||||
|
||||
When a function is passed to a higher order function e.g. a function
|
||||
passed to `concatMap` or `concatUnfold` then we want the function to be
|
||||
passed to `concatMap` or `unfoldMany` then we want the function to be
|
||||
inlined after the higher order is inlined so that proper fusion of the
|
||||
higher order function can occur. For such cases we usually add INLINE[1]
|
||||
on the function being passed to instruct GHC not to inline it too early.
|
||||
|
@ -30,7 +30,7 @@
|
||||
-- much less efficient when compared to combinators using 'Unfold'. For
|
||||
-- example, the 'Streamly.Prelude.concatMap' combinator which uses @a -> t m b@
|
||||
-- (where @t@ is a stream type) to generate streams is much less efficient
|
||||
-- compared to 'Streamly.Prelude.concatUnfold'.
|
||||
-- compared to 'Streamly.Prelude.unfoldMany'.
|
||||
--
|
||||
-- On the other hand, transformation operations on stream types are as
|
||||
-- efficient as transformations on 'Unfold'.
|
||||
|
@ -569,7 +569,7 @@ data FlattenState s a =
|
||||
|
||||
-- | Use the "read" unfold instead.
|
||||
--
|
||||
-- @flattenArrays = concatUnfold read@
|
||||
-- @flattenArrays = unfoldMany read@
|
||||
--
|
||||
-- We can try this if there are any fusion issues in the unfold.
|
||||
--
|
||||
@ -603,7 +603,7 @@ flattenArrays (D.Stream step state) = D.Stream step' (OuterLoop state)
|
||||
|
||||
-- | Use the "readRev" unfold instead.
|
||||
--
|
||||
-- @flattenArrays = concatUnfold readRev@
|
||||
-- @flattenArrays = unfoldMany readRev@
|
||||
--
|
||||
-- We can try this if there are any fusion issues in the unfold.
|
||||
--
|
||||
@ -987,7 +987,7 @@ fromStreamD :: (MonadIO m, Storable a) => D.Stream m a -> m (Array a)
|
||||
fromStreamD m = do
|
||||
buffered <- bufferChunks m
|
||||
len <- K.foldl' (+) 0 (K.map length buffered)
|
||||
fromStreamDN len $ D.concatUnfold read $ D.fromStreamK buffered
|
||||
fromStreamDN len $ D.unfoldMany read $ D.fromStreamK buffered
|
||||
|
||||
-- | Create an 'Array' from a list. The list must be of finite size.
|
||||
--
|
||||
|
@ -334,7 +334,7 @@ arraysOf n str = D.map unsafeFreeze $ MA.arraysOf n str
|
||||
|
||||
-- | Use the "read" unfold instead.
|
||||
--
|
||||
-- @flattenArrays = concatUnfold read@
|
||||
-- @flattenArrays = unfoldMany read@
|
||||
--
|
||||
-- We can try this if there are any fusion issues in the unfold.
|
||||
--
|
||||
@ -345,7 +345,7 @@ flattenArrays = MA.flattenArrays . D.map unsafeThaw
|
||||
|
||||
-- | Use the "readRev" unfold instead.
|
||||
--
|
||||
-- @flattenArrays = concatUnfold readRev@
|
||||
-- @flattenArrays = unfoldMany readRev@
|
||||
--
|
||||
-- We can try this if there are any fusion issues in the unfold.
|
||||
--
|
||||
|
@ -173,7 +173,7 @@ last arr = readIndex arr (length arr - 1)
|
||||
concat :: (IsStream t, MonadIO m, Prim a) => t m (Array a) -> t m a
|
||||
-- concat m = D.fromStreamD $ A.flattenArrays (D.toStreamD m)
|
||||
-- concat m = D.fromStreamD $ D.concatMap A.toStreamD (D.toStreamD m)
|
||||
concat m = D.fromStreamD $ D.concatUnfold read (D.toStreamD m)
|
||||
concat m = D.fromStreamD $ D.unfoldMany read (D.toStreamD m)
|
||||
|
||||
-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
|
||||
-- maximum specified size in bytes.
|
||||
|
@ -93,19 +93,19 @@ arraysOf n str = D.fromStreamD $ A.arraysOf n (D.toStreamD str)
|
||||
--
|
||||
-- Same as the following but more efficient:
|
||||
--
|
||||
-- > concat = Stream.concatUnfold Array.read
|
||||
-- > concat = Stream.unfoldMany Array.read
|
||||
--
|
||||
-- @since 0.7.0
|
||||
{-# INLINE concat #-}
|
||||
concat :: (IsStream t, MonadIO m, Storable a) => t m (Array a) -> t m a
|
||||
-- concat m = D.fromStreamD $ A.flattenArrays (D.toStreamD m)
|
||||
-- concat m = D.fromStreamD $ D.concatMap A.toStreamD (D.toStreamD m)
|
||||
concat m = D.fromStreamD $ D.concatUnfold A.read (D.toStreamD m)
|
||||
concat m = D.fromStreamD $ D.unfoldMany A.read (D.toStreamD m)
|
||||
|
||||
-- | Convert a stream of arrays into a stream of their elements reversing the
|
||||
-- contents of each array before flattening.
|
||||
--
|
||||
-- > concatRev = Stream.concatUnfold Array.readRev
|
||||
-- > concatRev = Stream.unfoldMany Array.readRev
|
||||
--
|
||||
-- @since 0.7.0
|
||||
{-# INLINE concatRev #-}
|
||||
|
@ -460,7 +460,7 @@ concatMapM f m = fromStreamD $ D.concatMapM (fmap toStreamD . f) (toStreamD m)
|
||||
-- concatMap f = 'concatMapM' (return . f)
|
||||
-- concatMap = 'concatMapWith' 'Serial.serial'
|
||||
-- concatMap f = 'concat . map f'
|
||||
-- concatMap f = 'concatUnfold' (UF.lmap f UF.fromStream)
|
||||
-- concatMap f = 'unfoldMany' (UF.lmap f UF.fromStream)
|
||||
-- @
|
||||
--
|
||||
-- @since 0.6.0
|
||||
|
@ -89,12 +89,13 @@ module Streamly.Internal.Data.Stream.IsStream.Expand
|
||||
|
||||
-- ** Append Many (Unfold)
|
||||
-- | Unfold and flatten streams.
|
||||
, unfoldMany
|
||||
, unfoldManyInterleave
|
||||
, unfoldManyRoundRobin
|
||||
, concatUnfold
|
||||
, concatUnfoldInterleave
|
||||
, concatUnfoldRoundrobin
|
||||
|
||||
-- ** Interpose
|
||||
-- | Insert effects between streams. Like concatUnfold but intersperses an
|
||||
-- | Insert effects between streams. Like unfoldMany but intersperses an
|
||||
-- effect between the streams. A special case of gintercalate.
|
||||
, interpose
|
||||
, interposeSuffix
|
||||
@ -102,7 +103,7 @@ module Streamly.Internal.Data.Stream.IsStream.Expand
|
||||
|
||||
-- ** Intercalate
|
||||
-- | Insert Streams between Streams.
|
||||
-- Like concatUnfold but intersperses streams from another source between
|
||||
-- Like unfoldMany but intersperses streams from another source between
|
||||
-- the streams from the first source.
|
||||
, intercalate
|
||||
, intercalateSuffix
|
||||
@ -449,40 +450,45 @@ mergeAsyncByM f m1 m2 =
|
||||
let par = Par.mkParallelD . toStreamD
|
||||
in D.mergeByM f (par m1) (par m2)
|
||||
|
||||
|
||||
-- @since 0.7.0
|
||||
{-# DEPRECATED concatUnfold "Please use unfoldMany instead." #-}
|
||||
{-# INLINE concatUnfold #-}
|
||||
concatUnfold ::(IsStream t, Monad m) => Unfold m a b -> t m a -> t m b
|
||||
concatUnfold u m = fromStreamD $ D.unfoldMany u (toStreamD m)
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Combine N Streams - concatUnfold
|
||||
-- Combine N Streams - unfoldMany
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- XXX Rename to unfoldMany
|
||||
--
|
||||
-- | Like 'concatMap' but uses an 'Unfold' for stream generation. Unlike
|
||||
-- 'concatMap' this can fuse the 'Unfold' code with the inner loop and
|
||||
-- therefore provide many times better performance.
|
||||
--
|
||||
-- @since 0.7.0
|
||||
{-# INLINE concatUnfold #-}
|
||||
concatUnfold ::(IsStream t, Monad m) => Unfold m a b -> t m a -> t m b
|
||||
concatUnfold u m = fromStreamD $ D.concatUnfold u (toStreamD m)
|
||||
-- @since 0.8.0
|
||||
{-# INLINE unfoldMany #-}
|
||||
unfoldMany ::(IsStream t, Monad m) => Unfold m a b -> t m a -> t m b
|
||||
unfoldMany u m = fromStreamD $ D.unfoldMany u (toStreamD m)
|
||||
|
||||
-- | Like 'concatUnfold' but interleaves the streams in the same way as
|
||||
-- | Like 'unfoldMany' but interleaves the streams in the same way as
|
||||
-- 'interleave' behaves instead of appending them.
|
||||
--
|
||||
-- /Pre-release/
|
||||
{-# INLINE concatUnfoldInterleave #-}
|
||||
concatUnfoldInterleave ::(IsStream t, Monad m)
|
||||
{-# INLINE unfoldManyInterleave #-}
|
||||
unfoldManyInterleave ::(IsStream t, Monad m)
|
||||
=> Unfold m a b -> t m a -> t m b
|
||||
concatUnfoldInterleave u m =
|
||||
fromStreamD $ D.concatUnfoldInterleave u (toStreamD m)
|
||||
unfoldManyInterleave u m =
|
||||
fromStreamD $ D.unfoldManyInterleave u (toStreamD m)
|
||||
|
||||
-- | Like 'concatUnfold' but executes the streams in the same way as
|
||||
-- | Like 'unfoldMany' but executes the streams in the same way as
|
||||
-- 'roundrobin'.
|
||||
--
|
||||
-- /Pre-release/
|
||||
{-# INLINE concatUnfoldRoundrobin #-}
|
||||
concatUnfoldRoundrobin ::(IsStream t, Monad m)
|
||||
{-# INLINE unfoldManyRoundRobin #-}
|
||||
unfoldManyRoundRobin ::(IsStream t, Monad m)
|
||||
=> Unfold m a b -> t m a -> t m b
|
||||
concatUnfoldRoundrobin u m =
|
||||
fromStreamD $ D.concatUnfoldRoundrobin u (toStreamD m)
|
||||
unfoldManyRoundRobin u m =
|
||||
fromStreamD $ D.unfoldManyRoundRobin u (toStreamD m)
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Combine N Streams - interpose
|
||||
@ -521,11 +527,11 @@ interposeSuffix x unf str =
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- XXX we can swap the order of arguments to gintercalate so that the
|
||||
-- definition of concatUnfold becomes simpler? The first stream should be
|
||||
-- definition of unfoldMany becomes simpler? The first stream should be
|
||||
-- infixed inside the second one. However, if we change the order in
|
||||
-- "interleave" as well similarly, then that will make it a bit unintuitive.
|
||||
--
|
||||
-- > concatUnfold unf str =
|
||||
-- > unfoldMany unf str =
|
||||
-- > gintercalate unf str (UF.nilM (\_ -> return ())) (repeat ())
|
||||
--
|
||||
-- | 'interleaveInfix' followed by unfold and concat.
|
||||
@ -547,7 +553,7 @@ gintercalate unf1 str1 unf2 str2 =
|
||||
-- will be starting with the second stream.
|
||||
|
||||
-- > intercalate seed unf str = gintercalate unf str unf (repeatM seed)
|
||||
-- > intercalate a unf str = concatUnfold unf $ intersperse a str
|
||||
-- > intercalate a unf str = unfoldMany unf $ intersperse a str
|
||||
--
|
||||
-- | 'intersperse' followed by unfold and concat.
|
||||
--
|
||||
@ -561,7 +567,7 @@ gintercalate unf1 str1 unf2 str2 =
|
||||
intercalate :: (IsStream t, Monad m)
|
||||
=> b -> Unfold m b c -> t m b -> t m c
|
||||
intercalate seed unf str = D.fromStreamD $
|
||||
D.concatUnfold unf $ D.intersperse seed (toStreamD str)
|
||||
D.unfoldMany unf $ D.intersperse seed (toStreamD str)
|
||||
|
||||
-- | 'interleaveSuffix' followed by unfold and concat.
|
||||
--
|
||||
@ -576,7 +582,7 @@ gintercalateSuffix unf1 str1 unf2 str2 =
|
||||
unf2 (D.toStreamD str2)
|
||||
|
||||
-- > intercalateSuffix seed unf str = gintercalateSuffix unf str unf (repeatM seed)
|
||||
-- > intercalateSuffix a unf str = concatUnfold unf $ intersperseSuffix a str
|
||||
-- > intercalateSuffix a unf str = unfoldMany unf $ intersperseSuffix a str
|
||||
--
|
||||
-- | 'intersperseSuffix' followed by unfold and concat.
|
||||
--
|
||||
@ -589,7 +595,7 @@ gintercalateSuffix unf1 str1 unf2 str2 =
|
||||
{-# INLINE intercalateSuffix #-}
|
||||
intercalateSuffix :: (IsStream t, Monad m)
|
||||
=> b -> Unfold m b c -> t m b -> t m c
|
||||
intercalateSuffix seed unf str = fromStreamD $ D.concatUnfold unf
|
||||
intercalateSuffix seed unf str = fromStreamD $ D.unfoldMany unf
|
||||
$ D.intersperseSuffix (return seed) (D.toStreamD str)
|
||||
|
||||
{-
|
||||
|
@ -10,7 +10,7 @@
|
||||
-- Prefer unfolds ("Streamly.Internal.Data.Unfold") over the combinators in
|
||||
-- this module. They are more powerful and efficient as they can be transformed
|
||||
-- and composed on the input side efficiently and they can fuse in nested
|
||||
-- operations (e.g. concatUnfold). All the combinators in this module can be
|
||||
-- operations (e.g. unfoldMany). All the combinators in this module can be
|
||||
-- expressed using unfolds with the same efficiency.
|
||||
--
|
||||
-- Operations in this module that are not in "Streamly.Internal.Data.Unfold":
|
||||
|
@ -35,13 +35,13 @@ module Streamly.Internal.Data.Stream.StreamD.Nesting
|
||||
|
||||
-- *** Appending
|
||||
-- | Append a stream after another. A special case of concatMap or
|
||||
-- concatUnfold.
|
||||
-- unfoldMany.
|
||||
AppendState(..)
|
||||
, append
|
||||
|
||||
-- *** Interleaving
|
||||
-- | Interleave elements from two streams alternately. A special case of
|
||||
-- concatUnfoldInterleave.
|
||||
-- unfoldManyInterleave.
|
||||
, InterleaveState(..)
|
||||
, interleave
|
||||
, interleaveMin
|
||||
@ -51,7 +51,7 @@ module Streamly.Internal.Data.Stream.StreamD.Nesting
|
||||
-- *** Scheduling
|
||||
-- | Execute streams alternately irrespective of whether they generate
|
||||
-- elements or not. Note 'interleave' would execute a stream until it
|
||||
-- yields an element. A special case of concatUnfoldRoundrobin.
|
||||
-- yields an element. A special case of unfoldManyRoundRobin.
|
||||
, roundRobin -- interleaveFair?/ParallelFair
|
||||
|
||||
-- *** Zipping
|
||||
@ -70,7 +70,7 @@ module Streamly.Internal.Data.Stream.StreamD.Nesting
|
||||
-- @
|
||||
-- concat: f (t m a) -> t m a
|
||||
-- concatMap: (a -> t m b) -> t m a -> t m b
|
||||
-- concatUnfold: Unfold m a b -> t m a -> t m b
|
||||
-- unfoldMany: Unfold m a b -> t m a -> t m b
|
||||
-- @
|
||||
|
||||
-- *** ConcatMap
|
||||
@ -83,19 +83,19 @@ module Streamly.Internal.Data.Stream.StreamD.Nesting
|
||||
-- | Generate streams by using an unfold on each element of an input
|
||||
-- stream, append the resulting streams and flatten. A special case of
|
||||
-- gintercalate.
|
||||
, concatUnfold
|
||||
, unfoldMany
|
||||
, ConcatUnfoldInterleaveState (..)
|
||||
, concatUnfoldInterleave
|
||||
, concatUnfoldRoundrobin
|
||||
, unfoldManyInterleave
|
||||
, unfoldManyRoundRobin
|
||||
|
||||
-- *** Interpose
|
||||
-- | Like concatUnfold but intersperses an effect between the streams. A
|
||||
-- | Like unfoldMany but intersperses an effect between the streams. A
|
||||
-- special case of gintercalate.
|
||||
, interpose
|
||||
, interposeSuffix
|
||||
|
||||
-- *** Intercalate
|
||||
-- | Like concatUnfold but intersperses streams from another source between
|
||||
-- | Like unfoldMany but intersperses streams from another source between
|
||||
-- the streams from the first source.
|
||||
, gintercalate
|
||||
, gintercalateSuffix
|
||||
@ -116,7 +116,7 @@ module Streamly.Internal.Data.Stream.StreamD.Nesting
|
||||
|
||||
-- ** Parsing
|
||||
-- | Parsing is opposite to flattening. 'parseMany' is dual to concatMap or
|
||||
-- concatUnfold. concatMap generates a stream from single values in a
|
||||
-- unfoldMany. concatMap generates a stream from single values in a
|
||||
-- stream and flattens, parseMany does the opposite of flattening by
|
||||
-- splitting the stream and then folds each such split to single value in
|
||||
-- the output stream.
|
||||
@ -477,7 +477,7 @@ mergeBy
|
||||
mergeBy cmp = mergeByM (\a b -> return $ cmp a b)
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Combine N Streams - concatUnfold
|
||||
-- Combine N Streams - unfoldMany
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
data ConcatUnfoldInterleaveState o i =
|
||||
@ -502,9 +502,9 @@ data ConcatUnfoldInterleaveState o i =
|
||||
-- Ideally, we need some scheduling bias to inner streams vs outer stream.
|
||||
-- Maybe we can configure the behavior.
|
||||
--
|
||||
{-# INLINE_NORMAL concatUnfoldInterleave #-}
|
||||
concatUnfoldInterleave :: Monad m => Unfold m a b -> Stream m a -> Stream m b
|
||||
concatUnfoldInterleave (Unfold istep inject) (Stream ostep ost) =
|
||||
{-# INLINE_NORMAL unfoldManyInterleave #-}
|
||||
unfoldManyInterleave :: Monad m => Unfold m a b -> Stream m a -> Stream m b
|
||||
unfoldManyInterleave (Unfold istep inject) (Stream ostep ost) =
|
||||
Stream step (ConcatUnfoldInterleaveOuter ost [])
|
||||
where
|
||||
{-# INLINE_LATE step #-}
|
||||
@ -553,11 +553,11 @@ concatUnfoldInterleave (Unfold istep inject) (Stream ostep ost) =
|
||||
--
|
||||
-- This could be inefficient if the tasks are too small.
|
||||
--
|
||||
-- Compared to concatUnfoldInterleave this one switches streams on Skips.
|
||||
-- Compared to unfoldManyInterleave this one switches streams on Skips.
|
||||
--
|
||||
{-# INLINE_NORMAL concatUnfoldRoundrobin #-}
|
||||
concatUnfoldRoundrobin :: Monad m => Unfold m a b -> Stream m a -> Stream m b
|
||||
concatUnfoldRoundrobin (Unfold istep inject) (Stream ostep ost) =
|
||||
{-# INLINE_NORMAL unfoldManyRoundRobin #-}
|
||||
unfoldManyRoundRobin :: Monad m => Unfold m a b -> Stream m a -> Stream m b
|
||||
unfoldManyRoundRobin (Unfold istep inject) (Stream ostep ost) =
|
||||
Stream step (ConcatUnfoldInterleaveOuter ost [])
|
||||
where
|
||||
{-# INLINE_LATE step #-}
|
||||
|
@ -1129,7 +1129,7 @@ reverse' m = Stream step Nothing
|
||||
return $ Yield x (Just (start, next))
|
||||
-}
|
||||
reverse' =
|
||||
A.flattenArraysRev -- concatUnfold A.readRev
|
||||
A.flattenArraysRev -- unfoldMany A.readRev
|
||||
. fromStreamK
|
||||
. K.reverse
|
||||
. toStreamK
|
||||
|
@ -75,7 +75,7 @@ module Streamly.Internal.Data.Stream.StreamD.Type
|
||||
|
||||
-- * Nesting
|
||||
, ConcatMapUState (..)
|
||||
, concatUnfold
|
||||
, unfoldMany
|
||||
, concatMap
|
||||
, concatMapM
|
||||
, FoldMany (..) -- for inspection testing
|
||||
@ -690,7 +690,7 @@ instance Applicative f => Applicative (Stream f) where
|
||||
(<*) = apDiscardSnd
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Combine N Streams - concatUnfold
|
||||
-- Combine N Streams - unfoldMany
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Define a unique structure to use in inspection testing
|
||||
@ -698,7 +698,7 @@ data ConcatMapUState o i =
|
||||
ConcatMapUOuter o
|
||||
| ConcatMapUInner o i
|
||||
|
||||
-- | @concatUnfold unfold stream@ uses @unfold@ to map the input stream elements
|
||||
-- | @unfoldMany unfold stream@ uses @unfold@ to map the input stream elements
|
||||
-- to streams and then flattens the generated streams into a single output
|
||||
-- stream.
|
||||
|
||||
@ -707,9 +707,9 @@ data ConcatMapUState o i =
|
||||
-- optimization via fusion. This can be many times more efficient than
|
||||
-- 'concatMap'.
|
||||
|
||||
{-# INLINE_NORMAL concatUnfold #-}
|
||||
concatUnfold :: Monad m => Unfold m a b -> Stream m a -> Stream m b
|
||||
concatUnfold (Unfold istep inject) (Stream ostep ost) =
|
||||
{-# INLINE_NORMAL unfoldMany #-}
|
||||
unfoldMany :: Monad m => Unfold m a b -> Stream m a -> Stream m b
|
||||
unfoldMany (Unfold istep inject) (Stream ostep ost) =
|
||||
Stream step (ConcatMapUOuter ost)
|
||||
where
|
||||
{-# INLINE_LATE step #-}
|
||||
@ -728,7 +728,7 @@ concatUnfold (Unfold istep inject) (Stream ostep ost) =
|
||||
Yield x i' -> Yield x (ConcatMapUInner o i')
|
||||
Skip i' -> Skip (ConcatMapUInner o i')
|
||||
Stop -> Skip (ConcatMapUOuter o)
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Combine N Streams - concatMap
|
||||
------------------------------------------------------------------------------
|
||||
|
@ -1181,7 +1181,7 @@ instance Monad m => Monad (Stream m) where
|
||||
|
||||
{-
|
||||
-- Like concatMap but generates stream using an unfold function. Similar to
|
||||
-- concatUnfold but for StreamK.
|
||||
-- unfoldMany but for StreamK.
|
||||
concatUnfoldr :: IsStream t
|
||||
=> (b -> t m (Maybe (a, b))) -> t m b -> t m a
|
||||
concatUnfoldr = undefined
|
||||
|
@ -17,13 +17,13 @@
|
||||
--
|
||||
-- This allows an important optimization to occur in several cases, making the
|
||||
-- 'Unfold' a more efficient abstraction. Consider the 'concatMap' and
|
||||
-- 'concatUnfold' operations, the latter is more efficient. 'concatMap'
|
||||
-- 'unfoldMany' operations, the latter is more efficient. 'concatMap'
|
||||
-- generates a new stream object from each element in the stream by applying
|
||||
-- the supplied function to the element, the stream object includes the "step"
|
||||
-- function as well as the initial "state" of the stream. Since the stream is
|
||||
-- generated dynamically the compiler does not know the step function or the
|
||||
-- state type statically at compile time, therefore, it cannot inline it. On
|
||||
-- the other hand in case of 'concatUnfold' the compiler has visibility into
|
||||
-- the other hand in case of 'unfoldMany' the compiler has visibility into
|
||||
-- the unfold's state generation function, therefore, the compiler knows all
|
||||
-- the types statically and it can inline the inject as well as the step
|
||||
-- functions, generating efficient code. Essentially, the stream is not opaque
|
||||
@ -844,7 +844,7 @@ fromProducer = Unfold step (return . FromSVarRead)
|
||||
-- stream.
|
||||
--
|
||||
-- @
|
||||
-- S.mapM_ print $ S.concatUnfold (UF.teeZipWith (,) UF.identity (UF.singleton sqrt)) $ S.fromList [1..10]
|
||||
-- S.mapM_ print $ S.unfoldMany (UF.teeZipWith (,) UF.identity (UF.singleton sqrt)) $ S.fromList [1..10]
|
||||
-- @
|
||||
--
|
||||
-- /Pre-release/
|
||||
|
@ -352,7 +352,7 @@ zipWithM f (Unfold step1 inject1) (Unfold step2 inject2) = Unfold step inject
|
||||
--
|
||||
-- @
|
||||
-- S.mapM_ print
|
||||
-- $ S.concatUnfold (UF.zipWith (,) UF.identity (UF.singleton sqrt))
|
||||
-- $ S.unfoldMany (UF.zipWith (,) UF.identity (UF.singleton sqrt))
|
||||
-- $ S.map (\x -> (x,x))
|
||||
-- $ S.fromList [1..10]
|
||||
-- @
|
||||
|
@ -596,6 +596,7 @@ module Streamly.Prelude
|
||||
, concatMap
|
||||
, concatMapM
|
||||
, concatUnfold
|
||||
, unfoldMany
|
||||
|
||||
-- ** Folding Containers of Streams
|
||||
-- | These are variants of standard 'Foldable' fold functions that use a
|
||||
|
@ -163,7 +163,7 @@ testArraysOf =
|
||||
monadicIO $ do
|
||||
xs <- run
|
||||
$ S.toList
|
||||
$ S.concatUnfold A.read
|
||||
$ S.unfoldMany A.read
|
||||
$ arraysOf 240
|
||||
$ S.fromList list
|
||||
assert (xs == list)
|
||||
|
@ -630,7 +630,7 @@ parseUnfold = do
|
||||
Producer.simplify (Source.parseManyD parser readSrc)
|
||||
xs <- run
|
||||
$ S.toList
|
||||
$ S.concatUnfold Unfold.fromList
|
||||
$ S.unfoldMany Unfold.fromList
|
||||
$ S.unfold streamParser src
|
||||
|
||||
listEquals (==) xs ls
|
||||
|
@ -1198,10 +1198,10 @@ transformCombineOpsCommon constr desc eq t = do
|
||||
forAll (choose (0, 100)) $ \n ->
|
||||
transform (concatMap (const [1..n]))
|
||||
t (S.concatMapM (const (return $ S.fromList [1..n])))
|
||||
prop (desc <> " concatUnfold") $
|
||||
prop (desc <> " unfoldMany") $
|
||||
forAll (choose (0, 100)) $ \n ->
|
||||
transform (concatMap (const [1..n]))
|
||||
t (S.concatUnfold (UF.lmap (const undefined)
|
||||
t (S.unfoldMany (UF.lmap (const undefined)
|
||||
$ UF.supply UF.fromList [1..n]))
|
||||
|
||||
toListFL :: Monad m => FL.Fold m a [a]
|
||||
|
Loading…
Reference in New Issue
Block a user