@@ -0,0 +1,246 @@
1+{-# LANGUAGE UndecidableInstances #-}
2+{-# OPTIONS_GHC -Wno-orphans #-}
3+
4+-- |
5+-- Module : Streamly.Internal.Data.Stream.Type
6+-- Copyright : (c) 2017 Composewell Technologies
7+--
8+-- License : BSD-3-Clause
9+-- Maintainer : streamly@composewell.com
10+-- Stability : experimental
11+-- Portability : GHC
12+--
13+module Streamly.Internal.Data.Stream.Type
14+ (
15+ Stream(..)
16+ , fromStreamD
17+ , toStreamD
18+ , foldWith
19+
20+ -- * Conversion operations
21+ , fromList
22+ , toList
23+
24+ -- * Transformation
25+ , list
26+ )
27+where
28+
29+import Control.Applicative (liftA2)
30+import Control.DeepSeq (NFData1(..))
31+import Control.Monad.Base (MonadBase(..), liftBaseDefault)
32+import Control.Monad.Catch (MonadThrow, throwM)
33+import Control.Monad.IO.Class (MonadIO(..))
34+import Control.Monad.Reader.Class (MonadReader(..))
35+import Control.Monad.State.Class (MonadState(..))
36+import Control.Monad.Trans.Class (MonadTrans(lift))
37+import Data.Functor.Identity (Identity(..), runIdentity)
38+#if __GLASGOW_HASKELL__ < 808
39+import Data.Semigroup (Semigroup(..))
40+#endif
41+import Streamly.Internal.Data.Fold.Type (Fold)
42+
43+import qualified Streamly.Internal.Data.Stream.Common as P
44+import qualified Streamly.Internal.Data.Stream.StreamD.Generate as D
45+import qualified Streamly.Internal.Data.Stream.StreamD.Transform as D
46+import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
47+import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
48+
49+import Prelude hiding (map, mapM, repeat, filter)
50+
51+#include "Instances.hs"
52+#include "inline.hs"
53+
54+-- $setup
55+-- >>> import qualified Streamly.Prelude as Stream
56+
57+------------------------------------------------------------------------------
58+-- Stream
59+------------------------------------------------------------------------------
60+
61+-- | For 'Stream' streams:
62+--
63+-- @
64+-- (<>) = 'Streamly.Prelude.serial' -- 'Semigroup'
65+-- (>>=) = flip . 'Streamly.Prelude.concatMapWith' 'Streamly.Prelude.serial' -- 'Monad'
66+-- @
67+--
68+-- A single 'Monad' bind behaves like a @for@ loop:
69+--
70+-- >>> :{
71+-- Stream.toList $ do
72+-- x <- Stream.fromList [1,2] -- foreach x in stream
73+-- return x
74+-- :}
75+-- [1,2]
76+--
77+-- Nested monad binds behave like nested @for@ loops:
78+--
79+-- >>> :{
80+-- Stream.toList $ do
81+-- x <- Stream.fromList [1,2] -- foreach x in stream
82+-- y <- Stream.fromList [3,4] -- foreach y in stream
83+-- return (x, y)
84+-- :}
85+-- [(1,3),(1,4),(2,3),(2,4)]
86+--
87+-- /Since: 0.2.0 ("Streamly")/
88+--
89+-- @since 0.8.0
90+newtype Stream m a = Stream {getStream :: K.Stream m a}
91+ -- XXX when deriving do we inherit an INLINE?
92+ deriving (Semigroup, Monoid, MonadTrans)
93+
94+------------------------------------------------------------------------------
95+-- Monad
96+------------------------------------------------------------------------------
97+
98+instance Monad m => Monad (Stream m) where
99+ return = pure
100+
101+ -- Benchmarks better with StreamD bind and pure:
102+ -- toList, filterAllout, *>, *<, >> (~2x)
103+ --
104+ -- pure = Stream . D.fromStreamD . D.fromPure
105+ -- m >>= f = D.fromStreamD $ D.concatMap (D.toStreamD . f) (D.toStreamD m)
106+
107+ -- Benchmarks better with CPS bind and pure:
108+ -- Prime sieve (25x)
109+ -- n binds, breakAfterSome, filterAllIn, state transformer (~2x)
110+ --
111+ {-# INLINE (>>=) #-}
112+ (>>=) (Stream m) f = Stream $ K.bindWith K.serial m (getStream . f)
113+
114+ {-# INLINE (>>) #-}
115+ (>>) = (*>)
116+
117+------------------------------------------------------------------------------
118+-- Other instances
119+------------------------------------------------------------------------------
120+
121+{-# INLINE apSerial #-}
122+apSerial :: Monad m => Stream m (a -> b) -> Stream m a -> Stream m b
123+apSerial (Stream m1) (Stream m2) =
124+ Stream $ D.toStreamK $ D.fromStreamK m1 <*> D.fromStreamK m2
125+
126+{-# INLINE apSequence #-}
127+apSequence :: Monad m => Stream m a -> Stream m b -> Stream m b
128+apSequence (Stream m1) (Stream m2) =
129+ Stream $ D.toStreamK $ D.fromStreamK m1 *> D.fromStreamK m2
130+
131+{-# INLINE apDiscardSnd #-}
132+apDiscardSnd :: Monad m => Stream m a -> Stream m b -> Stream m a
133+apDiscardSnd (Stream m1) (Stream m2) =
134+ Stream $ D.toStreamK $ D.fromStreamK m1 <* D.fromStreamK m2
135+
136+-- Note: we need to define all the typeclass operations because we want to
137+-- INLINE them.
138+instance Monad m => Applicative (Stream m) where
139+ {-# INLINE pure #-}
140+ pure = Stream . K.fromPure
141+
142+ {-# INLINE (<*>) #-}
143+ (<*>) = apSerial
144+ -- (<*>) = K.apSerial
145+
146+ {-# INLINE liftA2 #-}
147+ liftA2 f x = (<*>) (fmap f x)
148+
149+ {-# INLINE (*>) #-}
150+ (*>) = apSequence
151+ -- (*>) = K.apSerialDiscardFst
152+
153+ {-# INLINE (<*) #-}
154+ (<*) = apDiscardSnd
155+ -- (<*) = K.apSerialDiscardSnd
156+
157+MONAD_COMMON_INSTANCES(Stream,)
158+NFDATA1_INSTANCE(Stream)
159+
160+-- XXX Renamed to foldWith because Stream has a Foldable instance having
161+-- method fold.
162+--
163+-- | Fold a stream using the supplied left 'Fold' and reducing the resulting
164+-- expression strictly at each step. The behavior is similar to 'foldl''. A
165+-- 'Fold' can terminate early without consuming the full stream. See the
166+-- documentation of individual 'Fold's for termination behavior.
167+--
168+-- >>> Stream.foldWith Fold.sum (Stream.enumerateFromTo 1 100)
169+-- 5050
170+--
171+-- Folds never fail, therefore, they produce a default value even when no input
172+-- is provided. It means we can always fold an empty stream and get a valid
173+-- result. For example:
174+--
175+-- >>> Stream.foldWith Fold.sum Stream.nil
176+-- 0
177+--
178+-- However, 'foldMany' on an empty stream results in an empty stream.
179+-- Therefore, @Stream.foldWith f@ is not the same as @Stream.head . Stream.foldMany
180+-- f@.
181+--
182+-- @foldWith f = Stream.parse (Parser.fromFold f)@
183+--
184+-- /Pre-release/
185+{-# INLINE foldWith #-}
186+foldWith :: Monad m => Fold m a b -> Stream m a -> m b
187+foldWith fld m = D.fold fld $ toStreamD m
188+
189+-- XXX Renamed to "list" because fromList is present in IsList instance.
190+--
191+-- |
192+-- @
193+-- fromList = 'Prelude.foldr' 'K.cons' 'K.nil'
194+-- @
195+--
196+-- Construct a stream from a list of pure values. This is more efficient than
197+-- 'K.fromFoldable' for serial streams.
198+--
199+-- @since 0.4.0
200+{-# INLINE_EARLY list #-}
201+list :: Monad m => [a] -> Stream m a
202+list = fromStreamD . D.fromList
203+
204+------------------------------------------------------------------------------
205+-- Construction
206+------------------------------------------------------------------------------
207+
208+-- | Build a stream by unfolding a /monadic/ step function starting from a
209+-- seed. The step function returns the next element in the stream and the next
210+-- seed value. When it is done it returns 'Nothing' and the stream ends. For
211+-- example,
212+--
213+-- @
214+-- let f b =
215+-- if b > 3
216+-- then return Nothing
217+-- else print b >> return (Just (b, b + 1))
218+-- in drain $ unfoldrM f 0
219+-- @
220+-- @
221+-- 0
222+-- 1
223+-- 2
224+-- 3
225+-- @
226+--
227+-- /Pre-release/
228+--
229+{-# INLINE toStreamD #-}
230+toStreamD :: Applicative m => Stream m a -> D.Stream m a
231+toStreamD (Stream m) = D.fromStreamK m
232+
233+{-# INLINE fromStreamD #-}
234+fromStreamD :: Monad m => D.Stream m a -> Stream m a
235+fromStreamD m = Stream $ D.toStreamK m
236+
237+{-# INLINE_EARLY fromList #-}
238+fromList :: Monad m => [a] -> Stream m a
239+fromList = fromStreamD . D.fromList
240+
241+-- | Convert a stream into a list in the underlying monad.
242+--
243+-- @since 0.1.0
244+{-# INLINE toList #-}
245+toList :: Monad m => Stream m a -> m [a]
246+toList m = D.toList $ toStreamD m