on f2b2aa4 help sign in
352 lines 11 kB history raw
1{-# OPTIONS_GHC -Wno-orphans #-}
3#include "inline.hs"
5-- |
6-- Module : Streamly.Internal.Data.Stream.Prelude
7-- Copyright : (c) 2017 Composewell Technologies
8--
9-- License : BSD3
10-- Maintainer : streamly@composewell.com
11-- Stability : experimental
12-- Portability : GHC
13--
14--
15module Streamly.Internal.Data.Stream.Prelude
16 (
17 -- * Stream Conversion
18 fromStreamS
19 , toStreamS
21 -- * Running Effects
22 , drain
24 -- * Conversion operations
25 , fromList
26 , toList
28 -- * Fold operations
29 , foldrM
30 , foldrMx
31 , foldr
33 , foldlx'
34 , foldlMx'
35 , foldl'
36 , fold
38 -- Lazy left folds are useful only for reversing the stream
39 , foldlS
40 , foldlT
42 , scanlx'
43 , scanlMx'
44 , postscanlx'
45 , postscanlMx'
46 , postscanOnce
47 , scanOnce
49 -- * Zip style operations
50 , eqBy
51 , cmpBy
53 -- * Foldable instance
54 , minimum
55 , maximum
57 -- * Nesting
58 , K.concatMapBy
59 , K.concatMap
61 -- * Fold Utilities
62 , concatFoldableWith
63 , concatMapFoldableWith
64 , concatForFoldableWith
65 )
66where
68import Control.Monad.Trans.Class (MonadTrans(..))
69import Prelude hiding (foldr, minimum, maximum)
70import qualified Prelude
72import Streamly.Internal.Data.Fold.Type (Fold (..))
74#ifdef USE_STREAMK_ONLY
75import qualified Streamly.Internal.Data.Stream.StreamK as S
76#else
77import qualified Streamly.Internal.Data.Stream.StreamD as S
78#endif
80import Streamly.Internal.Data.Stream.StreamK (IsStream(..))
81import qualified Streamly.Internal.Data.Stream.StreamK as K
82import qualified Streamly.Internal.Data.Stream.StreamD as D
84------------------------------------------------------------------------------
85-- Conversion to and from direct style stream
86------------------------------------------------------------------------------
88-- These definitions are dependent on what is imported as S
89{-# INLINE fromStreamS #-}
90fromStreamS :: (IsStream t, Monad m) => S.Stream m a -> t m a
91fromStreamS = fromStream . S.toStreamK
93{-# INLINE toStreamS #-}
94toStreamS :: (IsStream t, Monad m) => t m a -> S.Stream m a
95toStreamS = S.fromStreamK . toStream
97------------------------------------------------------------------------------
98-- Conversions
99------------------------------------------------------------------------------
101{-# INLINE_EARLY drain #-}
102drain :: (IsStream t, Monad m) => t m a -> m ()
103drain m = D.drain $ D.fromStreamK (toStream m)
104{-# RULES "drain fallback to CPS" [1]
105 forall a. D.drain (D.fromStreamK a) = K.drain a #-}
107------------------------------------------------------------------------------
108-- Conversions
109------------------------------------------------------------------------------
111-- |
112-- @
113-- fromList = 'Prelude.foldr' 'K.cons' 'K.nil'
114-- @
115--
116-- Construct a stream from a list of pure values. This is more efficient than
117-- 'K.fromFoldable' for serial streams.
118--
119-- @since 0.4.0
120{-# INLINE_EARLY fromList #-}
121fromList :: (Monad m, IsStream t) => [a] -> t m a
122fromList = fromStreamS . S.fromList
123{-# RULES "fromList fallback to StreamK" [1]
124 forall a. S.toStreamK (S.fromList a) = K.fromFoldable a #-}
126-- | Convert a stream into a list in the underlying monad.
127--
128-- @since 0.1.0
129{-# INLINE toList #-}
130toList :: (Monad m, IsStream t) => t m a -> m [a]
131toList m = S.toList $ toStreamS m
133------------------------------------------------------------------------------
134-- Folds
135------------------------------------------------------------------------------
137{-# INLINE foldrM #-}
138foldrM :: (Monad m, IsStream t) => (a -> m b -> m b) -> m b -> t m a -> m b
139foldrM step acc m = S.foldrM step acc $ toStreamS m
141{-# INLINE foldrMx #-}
142foldrMx :: (Monad m, IsStream t)
143 => (a -> m x -> m x) -> m x -> (m x -> m b) -> t m a -> m b
144foldrMx step final project m = D.foldrMx step final project $ D.toStreamD m
146{-# INLINE foldr #-}
147foldr :: (Monad m, IsStream t) => (a -> b -> b) -> b -> t m a -> m b
148foldr f z = foldrM (\a b -> f a <$> b) (return z)
150-- | Like 'foldlx'', but with a monadic step function.
151--
152-- @since 0.7.0
153{-# INLINE foldlMx' #-}
154foldlMx' :: (IsStream t, Monad m)
155 => (x -> a -> m x) -> m x -> (x -> m b) -> t m a -> m b
156foldlMx' step begin done m = S.foldlMx' step begin done $ toStreamS m
158-- | Strict left fold with an extraction function. Like the standard strict
159-- left fold, but applies a user supplied extraction function (the third
160-- argument) to the folded value at the end. This is designed to work with the
161-- @foldl@ library. The suffix @x@ is a mnemonic for extraction.
162--
163-- @since 0.7.0
164{-# INLINE foldlx' #-}
165foldlx' :: (IsStream t, Monad m)
166 => (x -> a -> x) -> x -> (x -> b) -> t m a -> m b
167foldlx' step begin done m = S.foldlx' step begin done $ toStreamS m
169-- | Strict left associative fold.
170--
171-- @since 0.2.0
172{-# INLINE foldl' #-}
173foldl' :: (Monad m, IsStream t) => (b -> a -> b) -> b -> t m a -> m b
174foldl' step begin m = S.foldl' step begin $ toStreamS m
176{-# INLINE foldlS #-}
177foldlS :: IsStream t => (t m b -> a -> t m b) -> t m b -> t m a -> t m b
178foldlS = K.foldlS
180-- | Lazy left fold to a transformer monad.
181--
182-- For example, to reverse a stream:
183--
184-- > S.toList $ S.foldlT (flip S.cons) S.nil $ (S.fromList [1..5] :: SerialT IO Int)
185--
186{-# INLINE foldlT #-}
187foldlT :: (Monad m, IsStream t, Monad (s m), MonadTrans s)
188 => (s m b -> a -> s m b) -> s m b -> t m a -> s m b
189foldlT f z s = S.foldlT f z (toStreamS s)
191{-# INLINE fold #-}
192fold :: (Monad m, IsStream t) => Fold m a b -> t m a -> m b
193fold fld m = S.fold fld $ toStreamS m
195------------------------------------------------------------------------------
196-- Scans
197------------------------------------------------------------------------------
199-- postscanlM' followed by mapM
200{-# INLINE postscanlMx' #-}
201postscanlMx' :: (IsStream t, Monad m)
202 => (x -> a -> m x) -> m x -> (x -> m b) -> t m a -> t m b
203postscanlMx' step begin done m =
204 D.fromStreamD $ D.postscanlMx' step begin done $ D.toStreamD m
206-- postscanl' followed by map
207{-# INLINE postscanlx' #-}
208postscanlx' :: (IsStream t, Monad m)
209 => (x -> a -> x) -> x -> (x -> b) -> t m a -> t m b
210postscanlx' step begin done m =
211 D.fromStreamD $ D.postscanlx' step begin done $ D.toStreamD m
213-- scanlM' followed by mapM
214--
215{-# INLINE scanlMx' #-}
216scanlMx' :: (IsStream t, Monad m)
217 => (x -> a -> m x) -> m x -> (x -> m b) -> t m a -> t m b
218scanlMx' step begin done m =
219 D.fromStreamD $ D.scanlMx' step begin done $ D.toStreamD m
221{-# INLINE_NORMAL postscanOnce #-}
222postscanOnce :: (IsStream t, Monad m)
223 => Fold m a b -> t m a -> t m b
224postscanOnce fld m =
225 D.fromStreamD $ D.postscanOnce fld $ D.toStreamD m
227{-# INLINE scanOnce #-}
228scanOnce :: (IsStream t, Monad m)
229 => Fold m a b -> t m a -> t m b
230scanOnce fld m = D.fromStreamD $ D.scanOnce fld $ D.toStreamD m
232-- scanl followed by map
233--
234-- | Strict left scan with an extraction function. Like 'scanl'', but applies a
235-- user supplied extraction function (the third argument) at each step. This is
236-- designed to work with the @foldl@ library. The suffix @x@ is a mnemonic for
237-- extraction.
238--
239-- @since 0.7.0
240{-# INLINE scanlx' #-}
241scanlx' :: (IsStream t, Monad m)
242 => (x -> a -> x) -> x -> (x -> b) -> t m a -> t m b
243scanlx' step begin done m =
244 fromStreamS $ S.scanlx' step begin done $ toStreamS m
246------------------------------------------------------------------------------
247-- Comparison
248------------------------------------------------------------------------------
250-- | Compare two streams for equality
251--
252-- @since 0.5.3
253{-# INLINE eqBy #-}
254eqBy :: (IsStream t, Monad m) => (a -> b -> Bool) -> t m a -> t m b -> m Bool
255eqBy f m1 m2 = D.eqBy f (D.toStreamD m1) (D.toStreamD m2)
257-- | Compare two streams
258--
259-- @since 0.5.3
260{-# INLINE cmpBy #-}
261cmpBy
262 :: (IsStream t, Monad m)
263 => (a -> b -> Ordering) -> t m a -> t m b -> m Ordering
264cmpBy f m1 m2 = D.cmpBy f (D.toStreamD m1) (D.toStreamD m2)
266{-# INLINE minimum #-}
267minimum :: (IsStream t, Monad m, Ord a) => t m a -> m (Maybe a)
268minimum m = S.minimum (toStreamS m)
270{-# INLINE maximum #-}
271maximum :: (IsStream t, Monad m, Ord a) => t m a -> m (Maybe a)
272maximum m = S.maximum (toStreamS m)
274------------------------------------------------------------------------------
275-- Fold Utilities
276------------------------------------------------------------------------------
278{-
279-- XXX do we have facilities in Foldable to fold any Foldable in this manner?
280--
281-- | Perform a pair wise bottom up hierarchical fold of elements in the
282-- container using the given function as the merge function.
283--
284-- This will perform a balanced merge sort if the merge function is
285-- 'mergeBy compare'.
286--
287-- @since 0.7.0
288{-# INLINABLE foldbWith #-}
289foldbWith :: IsStream t
290 => (t m a -> t m a -> t m a) -> SerialT Identity (t m a) -> t m a
291foldbWith f = K.foldb f K.nil
292-}
295-- | A variant of 'Data.Foldable.fold' that allows you to fold a 'Foldable'
296-- container of streams using the specified stream sum operation.
297--
298-- @concatFoldableWith 'async' $ map return [1..3]@
299--
300-- Equivalent to:
301--
302-- @
303-- concatFoldableWith f = Prelude.foldr f S.nil
304-- concatFoldableWith f = S.concatMapFoldableWith f id
305-- @
306--
307-- /Since: 0.8.0 (Renamed foldWith to concatFoldableWith)/
308--
309-- /Since: 0.1.0 ("Streamly")/
310{-# INLINABLE concatFoldableWith #-}
311concatFoldableWith :: (IsStream t, Foldable f)
312 => (t m a -> t m a -> t m a) -> f (t m a) -> t m a
313concatFoldableWith f = Prelude.foldr f K.nil
315-- | A variant of 'foldMap' that allows you to map a monadic streaming action
316-- on a 'Foldable' container and then fold it using the specified stream merge
317-- operation.
318--
319-- @concatMapFoldableWith 'async' return [1..3]@
320--
321-- Equivalent to:
322--
323-- @
324-- concatMapFoldableWith f g = Prelude.foldr (f . g) S.nil
325-- concatMapFoldableWith f g xs = S.concatMapWith f g (S.fromFoldable xs)
326-- @
327--
328-- /Since: 0.8.0 (Renamed foldMapWith to concatMapFoldableWith)/
329--
330-- /Since: 0.1.0 ("Streamly")/
331{-# INLINABLE concatMapFoldableWith #-}
332concatMapFoldableWith :: (IsStream t, Foldable f)
333 => (t m b -> t m b -> t m b) -> (a -> t m b) -> f a -> t m b
334concatMapFoldableWith f g = Prelude.foldr (f . g) K.nil
336-- | Like 'concatMapFoldableWith' but with the last two arguments reversed i.e. the
337-- monadic streaming function is the last argument.
338--
339-- Equivalent to:
340--
341-- @
342-- concatForFoldableWith f xs g = Prelude.foldr (f . g) S.nil xs
343-- concatForFoldableWith = flip S.concatMapFoldableWith
344-- @
345--
346-- /Since: 0.8.0 (Renamed forEachWith to concatForFoldableWith)/
347--
348-- /Since: 0.1.0 ("Streamly")/
349{-# INLINABLE concatForFoldableWith #-}
350concatForFoldableWith :: (IsStream t, Foldable f)
351 => (t m b -> t m b -> t m b) -> f a -> (a -> t m b) -> t m b
352concatForFoldableWith f xs g = Prelude.foldr (f . g) K.nil xs