on 2255dac help sign in
296 lines 9.0 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.Streams.Prelude
11-- Copyright : (c) 2017 Harendra Kumar
12--
13-- License : BSD3
14-- Maintainer : harendra.kumar@gmail.com
15-- Stability : experimental
16-- Portability : GHC
17--
18--
19module Streamly.Streams.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'
41 -- Lazy left folds are useful only for reversing the stream
42 , foldlS
43 , foldlT
45 , scanlx'
46 , scanlMx'
47 , postscanlx'
48 , postscanlMx'
50 -- * Zip style operations
51 , eqBy
52 , cmpBy
54 -- * Nesting
55 , K.concatMapBy
56 , K.concatMap
58 -- * Fold Utilities
59 , foldWith
60 , foldMapWith
61 , forEachWith
62 )
63where
65import Control.Monad.Trans (MonadTrans(..))
66import Prelude hiding (foldr)
67import qualified Prelude
69#ifdef USE_STREAMK_ONLY
70import qualified Streamly.Streams.StreamK as S
71#else
72import qualified Streamly.Streams.StreamD as S
73#endif
75import Streamly.Streams.StreamK (IsStream(..))
76import qualified Streamly.Streams.StreamK as K
77import qualified Streamly.Streams.StreamD as D
79------------------------------------------------------------------------------
80-- Conversion to and from direct style stream
81------------------------------------------------------------------------------
83-- These definitions are dependent on what is imported as S
84{-# INLINE fromStreamS #-}
85fromStreamS :: (IsStream t, Monad m) => S.Stream m a -> t m a
86fromStreamS = fromStream . S.toStreamK
88{-# INLINE toStreamS #-}
89toStreamS :: (IsStream t, Monad m) => t m a -> S.Stream m a
90toStreamS = S.fromStreamK . toStream
92------------------------------------------------------------------------------
93-- Conversions
94------------------------------------------------------------------------------
96{-# INLINE_EARLY drain #-}
97drain :: (IsStream t, Monad m) => t m a -> m ()
98drain m = D.drain $ D.fromStreamK (toStream m)
99{-# RULES "drain fallback to CPS" [1]
100 forall a. D.drain (D.fromStreamK a) = K.drain a #-}
102------------------------------------------------------------------------------
103-- Conversions
104------------------------------------------------------------------------------
106-- |
107-- @
108-- fromList = 'Prelude.foldr' 'K.cons' 'K.nil'
109-- @
110--
111-- Construct a stream from a list of pure values. This is more efficient than
112-- 'K.fromFoldable' for serial streams.
113--
114-- @since 0.4.0
115{-# INLINE_EARLY fromList #-}
116fromList :: (Monad m, IsStream t) => [a] -> t m a
117fromList = fromStreamS . S.fromList
118{-# RULES "fromList fallback to StreamK" [1]
119 forall a. S.toStreamK (S.fromList a) = K.fromFoldable a #-}
121-- | Convert a stream into a list in the underlying monad.
122--
123-- @since 0.1.0
124{-# INLINE toList #-}
125toList :: (Monad m, IsStream t) => t m a -> m [a]
126toList m = S.toList $ toStreamS m
128------------------------------------------------------------------------------
129-- Folds
130------------------------------------------------------------------------------
132{-# INLINE foldrM #-}
133foldrM :: (Monad m, IsStream t) => (a -> m b -> m b) -> m b -> t m a -> m b
134foldrM step acc m = S.foldrM step acc $ toStreamS m
136{-# INLINE foldrMx #-}
137foldrMx :: (Monad m, IsStream t)
138 => (a -> m x -> m x) -> m x -> (m x -> m b) -> t m a -> m b
139foldrMx step final project m = D.foldrMx step final project $ D.toStreamD m
141{-# INLINE foldr #-}
142foldr :: (Monad m, IsStream t) => (a -> b -> b) -> b -> t m a -> m b
143foldr f z = foldrM (\a b -> b >>= return . f a) (return z)
145-- | Like 'foldlx'', but with a monadic step function.
146--
147-- @since 0.7.0
148{-# INLINE foldlMx' #-}
149foldlMx' :: (IsStream t, Monad m)
150 => (x -> a -> m x) -> m x -> (x -> m b) -> t m a -> m b
151foldlMx' step begin done m = S.foldlMx' step begin done $ toStreamS m
153-- | Strict left fold with an extraction function. Like the standard strict
154-- left fold, but applies a user supplied extraction function (the third
155-- argument) to the folded value at the end. This is designed to work with the
156-- @foldl@ library. The suffix @x@ is a mnemonic for extraction.
157--
158-- @since 0.7.0
159{-# INLINE foldlx' #-}
160foldlx' :: (IsStream t, Monad m)
161 => (x -> a -> x) -> x -> (x -> b) -> t m a -> m b
162foldlx' step begin done m = S.foldlx' step begin done $ toStreamS m
164-- | Strict left associative fold.
165--
166-- @since 0.2.0
167{-# INLINE foldl' #-}
168foldl' :: (Monad m, IsStream t) => (b -> a -> b) -> b -> t m a -> m b
169foldl' step begin m = S.foldl' step begin $ toStreamS m
171{-# INLINE foldlS #-}
172foldlS :: IsStream t => (t m b -> a -> t m b) -> t m b -> t m a -> t m b
173foldlS = K.foldlS
175-- | Lazy left fold to a transformer monad.
176--
177-- For example, to reverse a stream:
178--
179-- > S.toList $ S.foldlT (flip S.cons) S.nil $ (S.fromList [1..5] :: SerialT IO Int)
180--
181{-# INLINE foldlT #-}
182foldlT :: (Monad m, IsStream t, Monad (s m), MonadTrans s)
183 => (s m b -> a -> s m b) -> s m b -> t m a -> s m b
184foldlT f z s = S.foldlT f z (toStreamS s)
186------------------------------------------------------------------------------
187-- Scans
188------------------------------------------------------------------------------
190-- postscanlM' followed by mapM
191{-# INLINE postscanlMx' #-}
192postscanlMx' :: (IsStream t, Monad m)
193 => (x -> a -> m x) -> m x -> (x -> m b) -> t m a -> t m b
194postscanlMx' step begin done m =
195 D.fromStreamD $ D.postscanlMx' step begin done $ D.toStreamD m
197-- postscanl' followed by map
198{-# INLINE postscanlx' #-}
199postscanlx' :: (IsStream t, Monad m)
200 => (x -> a -> x) -> x -> (x -> b) -> t m a -> t m b
201postscanlx' step begin done m =
202 D.fromStreamD $ D.postscanlx' step begin done $ D.toStreamD m
204-- scanlM' followed by mapM
205--
206{-# INLINE scanlMx' #-}
207scanlMx' :: (IsStream t, Monad m)
208 => (x -> a -> m x) -> m x -> (x -> m b) -> t m a -> t m b
209scanlMx' step begin done m =
210 D.fromStreamD $ D.scanlMx' step begin done $ D.toStreamD m
212-- scanl followed by map
213--
214-- | Strict left scan with an extraction function. Like 'scanl'', but applies a
215-- user supplied extraction function (the third argument) at each step. This is
216-- designed to work with the @foldl@ library. The suffix @x@ is a mnemonic for
217-- extraction.
218--
219-- @since 0.7.0
220{-# INLINE scanlx' #-}
221scanlx' :: (IsStream t, Monad m)
222 => (x -> a -> x) -> x -> (x -> b) -> t m a -> t m b
223scanlx' step begin done m =
224 fromStreamS $ S.scanlx' step begin done $ toStreamS m
226------------------------------------------------------------------------------
227-- Comparison
228------------------------------------------------------------------------------
230-- | Compare two streams for equality
231--
232-- @since 0.5.3
233{-# INLINE eqBy #-}
234eqBy :: (IsStream t, Monad m) => (a -> b -> Bool) -> t m a -> t m b -> m Bool
235eqBy f m1 m2 = D.eqBy f (D.toStreamD m1) (D.toStreamD m2)
237-- | Compare two streams
238--
239-- @since 0.5.3
240{-# INLINE cmpBy #-}
241cmpBy
242 :: (IsStream t, Monad m)
243 => (a -> b -> Ordering) -> t m a -> t m b -> m Ordering
244cmpBy f m1 m2 = D.cmpBy f (D.toStreamD m1) (D.toStreamD m2)
246------------------------------------------------------------------------------
247-- Fold Utilities
248------------------------------------------------------------------------------
250{-
251-- XXX do we have facilities in Foldable to fold any Foldable in this manner?
252--
253-- | Perform a pair wise bottom up hierarchical fold of elements in the
254-- container using the given function as the merge function.
255--
256-- This will perform a balanced merge sort if the merge function is
257-- 'mergeBy compare'.
258--
259-- @since 0.7.0
260{-# INLINABLE foldbWith #-}
261foldbWith :: IsStream t
262 => (t m a -> t m a -> t m a) -> SerialT Identity (t m a) -> t m a
263foldbWith f = K.foldb f K.nil
264-}
266-- | A variant of 'Data.Foldable.fold' that allows you to fold a 'Foldable'
267-- container of streams using the specified stream sum operation.
268--
269-- @foldWith 'async' $ map return [1..3]@
270--
271-- @since 0.1.0
272{-# INLINABLE foldWith #-}
273foldWith :: (IsStream t, Foldable f)
274 => (t m a -> t m a -> t m a) -> f (t m a) -> t m a
275foldWith f = Prelude.foldr f K.nil
277-- | A variant of 'foldMap' that allows you to map a monadic streaming action
278-- on a 'Foldable' container and then fold it using the specified stream sum
279-- operation.
280--
281-- @foldMapWith 'async' return [1..3]@
282--
283-- @since 0.1.0
284{-# INLINABLE foldMapWith #-}
285foldMapWith :: (IsStream t, Foldable f)
286 => (t m b -> t m b -> t m b) -> (a -> t m b) -> f a -> t m b
287foldMapWith f g = Prelude.foldr (f . g) K.nil
289-- | Like 'foldMapWith' but with the last two arguments reversed i.e. the
290-- monadic streaming function is the last argument.
291--
292-- @since 0.1.0
293{-# INLINABLE forEachWith #-}
294forEachWith :: (IsStream t, Foldable f)
295 => (t m b -> t m b -> t m b) -> f a -> (a -> t m b) -> t m b
296forEachWith f xs g = Prelude.foldr (f . g) K.nil xs