@@ -0,0 +1,246 @@
1+{-# LANGUAGE UndecidableInstances #-}
2+{-# OPTIONS_GHC -Wno-orphans #-}
5+-- Module : Streamly.Internal.Data.Stream.Type
6+-- Copyright : (c) 2017 Composewell Technologies
8+-- License : BSD-3-Clause
9+-- Maintainer : streamly@composewell.com
10+-- Stability : experimental
13+module Streamly.Internal.Data.Stream.Type
20+ -- * Conversion operations
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(..))
41+import Streamly.Internal.Data.Fold.Type (Fold)
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
49+import Prelude hiding (map, mapM, repeat, filter)
51+#include "Instances.hs"
55+-- >>> import qualified Streamly.Prelude as Stream
57+------------------------------------------------------------------------------
59+------------------------------------------------------------------------------
61+-- | For 'Stream' streams:
64+-- (<>) = 'Streamly.Prelude.serial' -- 'Semigroup'
65+-- (>>=) = flip . 'Streamly.Prelude.concatMapWith' 'Streamly.Prelude.serial' -- 'Monad'
68+-- A single 'Monad' bind behaves like a @for@ loop:
72+-- x <- Stream.fromList [1,2] -- foreach x in stream
77+-- Nested monad binds behave like nested @for@ loops:
81+-- x <- Stream.fromList [1,2] -- foreach x in stream
82+-- y <- Stream.fromList [3,4] -- foreach y in stream
85+-- [(1,3),(1,4),(2,3),(2,4)]
87+-- /Since: 0.2.0 ("Streamly")/
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)
94+------------------------------------------------------------------------------
96+------------------------------------------------------------------------------
98+instance Monad m => Monad (Stream m) where
101+ -- Benchmarks better with StreamD bind and pure:
102+ -- toList, filterAllout, *>, *<, >> (~2x)
104+ -- pure = Stream . D.fromStreamD . D.fromPure
105+ -- m >>= f = D.fromStreamD $ D.concatMap (D.toStreamD . f) (D.toStreamD m)
107+ -- Benchmarks better with CPS bind and pure:
108+ -- Prime sieve (25x)
109+ -- n binds, breakAfterSome, filterAllIn, state transformer (~2x)
111+ {-# INLINE (>>=) #-}
112+ (>>=) (Stream m) f = Stream $ K.bindWith K.serial m (getStream . f)
117+------------------------------------------------------------------------------
119+------------------------------------------------------------------------------
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
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
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
136+-- Note: we need to define all the typeclass operations because we want to
138+instance Monad m => Applicative (Stream m) where
140+ pure = Stream . K.fromPure
142+ {-# INLINE (<*>) #-}
144+ -- (<*>) = K.apSerial
146+ {-# INLINE liftA2 #-}
147+ liftA2 f x = (<*>) (fmap f x)
151+ -- (*>) = K.apSerialDiscardFst
155+ -- (<*) = K.apSerialDiscardSnd
157+MONAD_COMMON_INSTANCES(Stream,)
158+NFDATA1_INSTANCE(Stream)
160+-- XXX Renamed to foldWith because Stream has a Foldable instance having
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.
168+-- >>> Stream.foldWith Fold.sum (Stream.enumerateFromTo 1 100)
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:
175+-- >>> Stream.foldWith Fold.sum Stream.nil
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
182+-- @foldWith f = Stream.parse (Parser.fromFold f)@
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
189+-- XXX Renamed to "list" because fromList is present in IsList instance.
193+-- fromList = 'Prelude.foldr' 'K.cons' 'K.nil'
196+-- Construct a stream from a list of pure values. This is more efficient than
197+-- 'K.fromFoldable' for serial streams.
200+{-# INLINE_EARLY list #-}
201+list :: Monad m => [a] -> Stream m a
202+list = fromStreamD . D.fromList
204+------------------------------------------------------------------------------
206+------------------------------------------------------------------------------
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
216+-- then return Nothing
217+-- else print b >> return (Just (b, b + 1))
218+-- in drain $ unfoldrM f 0
229+{-# INLINE toStreamD #-}
230+toStreamD :: Applicative m => Stream m a -> D.Stream m a
231+toStreamD (Stream m) = D.fromStreamK m
233+{-# INLINE fromStreamD #-}
234+fromStreamD :: Monad m => D.Stream m a -> Stream m a
235+fromStreamD m = Stream $ D.toStreamK m
237+{-# INLINE_EARLY fromList #-}
238+fromList :: Monad m => [a] -> Stream m a
239+fromList = fromStreamD . D.fromList
241+-- | Convert a stream into a list in the underlying monad.
244+{-# INLINE toList #-}
245+toList :: Monad m => Stream m a -> m [a]
246+toList m = D.toList $ toStreamD m