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