@@ -37,6 +37,8 @@ module Streamly.Internal.Data.Stream.Type
40import Control.Applicative (liftA2)
42import Control.Applicative (liftA2)
41import Control.DeepSeq (NFData(..), NFData1(..))
43import Control.DeepSeq (NFData(..), NFData1(..))
42import Control.Monad.Base (MonadBase(..), liftBaseDefault)
44import Control.Monad.Base (MonadBase(..), liftBaseDefault)
@@ -63,9 +65,6 @@ import qualified Streamly.Internal.Data.Stream.Common as P
63import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
65import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
64import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
66import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
66−#include "Instances.hs"
70-- >>> import qualified Streamly.Data.Fold as Fold
69-- >>> import qualified Streamly.Data.Fold as Fold
71-- >>> import qualified Streamly.Internal.Data.Unfold as Unfold
70-- >>> import qualified Streamly.Internal.Data.Unfold as Unfold
@@ -112,19 +111,19 @@ newtype Stream m a = Stream (K.Stream m a)
112-- Conversions
111-- Conversions
113------------------------------------------------------------------------------
112------------------------------------------------------------------------------
115−{-# INLINE fromStreamK #-}
114+{-# INLINE_EARLY fromStreamK #-}
116fromStreamK :: K.Stream m a -> Stream m a
115fromStreamK :: K.Stream m a -> Stream m a
117fromStreamK = Stream
116fromStreamK = Stream
119−{-# INLINE toStreamK #-}
118+{-# INLINE_EARLY toStreamK #-}
120toStreamK :: Stream m a -> K.Stream m a
119toStreamK :: Stream m a -> K.Stream m a
121toStreamK (Stream k) = k
120toStreamK (Stream k) = k
123−{-# INLINE fromStreamD #-}
122+{-# INLINE_EARLY fromStreamD #-}
124fromStreamD :: Monad m => D.Stream m a -> Stream m a
123fromStreamD :: Monad m => D.Stream m a -> Stream m a
125fromStreamD = fromStreamK . D.toStreamK
124fromStreamD = fromStreamK . D.toStreamK
127−{-# INLINE toStreamD #-}
126+{-# INLINE_EARLY toStreamD #-}
128toStreamD :: Applicative m => Stream m a -> D.Stream m a
127toStreamD :: Applicative m => Stream m a -> D.Stream m a
129toStreamD = D.fromStreamK . toStreamK
128toStreamD = D.fromStreamK . toStreamK
@@ -150,30 +149,19 @@ cmpBy
150cmpBy f m1 m2 = D.cmpBy f (toStreamD m1) (toStreamD m2)
149cmpBy f m1 m2 = D.cmpBy f (toStreamD m1) (toStreamD m2)
152------------------------------------------------------------------------------
151------------------------------------------------------------------------------
153−-- Monad
152+-- Functor
154------------------------------------------------------------------------------
153------------------------------------------------------------------------------
156−instance Monad m => Monad (Stream m) where
155+instance Monad m => Functor (Stream m) where
159− -- Benchmarks better with StreamD bind and pure:
160− -- toList, filterAllout, *>, *<, >> (~2x)
162− -- pure = Stream . D.fromStreamD . D.fromPure
163− -- m >>= f = D.fromStreamD $ D.concatMap (D.toStreamD . f) (D.toStreamD m)
165− -- Benchmarks better with CPS bind and pure:
166− -- Prime sieve (25x)
167− -- n binds, breakAfterSome, filterAllIn, state transformer (~2x)
169− {-# INLINE (>>=) #-}
156+ {-# INLINE fmap #-}
170− (>>=) m f = fromStreamK $ K.bindWith K.serial (toStreamK m) (toStreamK . f)
157+ -- IMPORTANT: do not use eta reduction.
158+ fmap f m = fromStreamD $ D.mapM (return . f) $ toStreamD m
172− {-# INLINE (>>) #-}
160+ {-# INLINE (<$) #-}
173− (>>) = (*>)
161+ (<$) = fmap . const
175------------------------------------------------------------------------------
163------------------------------------------------------------------------------
176−-- Other instances
164+-- Applicative
177------------------------------------------------------------------------------
165------------------------------------------------------------------------------
179{-# INLINE apSerial #-}
167{-# INLINE apSerial #-}
@@ -212,12 +200,214 @@ instance Monad m => Applicative (Stream m) where
212 (<*) = apDiscardSnd
200 (<*) = apDiscardSnd
213 -- (<*) = K.apSerialDiscardSnd
201 -- (<*) = K.apSerialDiscardSnd
203+------------------------------------------------------------------------------
205+------------------------------------------------------------------------------
207+instance Monad m => Monad (Stream m) where
210+ -- Benchmarks better with StreamD bind and pure:
211+ -- toList, filterAllout, *>, *<, >> (~2x)
213+ -- pure = Stream . D.fromStreamD . D.fromPure
214+ -- m >>= f = D.fromStreamD $ D.concatMap (D.toStreamD . f) (D.toStreamD m)
216+ -- Benchmarks better with CPS bind and pure:
217+ -- Prime sieve (25x)
218+ -- n binds, breakAfterSome, filterAllIn, state transformer (~2x)
220+ {-# INLINE (>>=) #-}
221+ (>>=) m f = fromStreamK $ K.bindWith K.serial (toStreamK m) (toStreamK . f)
226+------------------------------------------------------------------------------
228+------------------------------------------------------------------------------
215-- XXX Need to remove the MonadBase instance
230-- XXX Need to remove the MonadBase instance
216−MONAD_COMMON_INSTANCES(Stream,)
231+instance (MonadBase b m, Monad m ) => MonadBase b (Stream m) where
217−LIST_INSTANCES(Stream)
232+ liftBase = liftBaseDefault
218−NFDATA1_INSTANCE(Stream)
233+
219−FOLDABLE_INSTANCE(Stream)
234+instance (MonadIO m) => MonadIO (Stream m) where
220−TRAVERSABLE_INSTANCE(Stream)
235+ liftIO = lift . liftIO
237+instance (MonadThrow m) => MonadThrow (Stream m) where
238+ throwM = lift . throwM
240+instance (MonadReader r m) => MonadReader r (Stream m) where
243+ local f (Stream m) = Stream $ K.withLocal f m
245+instance (MonadState s m) => MonadState s (Stream m) where
250+ put x = lift (put x)
252+ {-# INLINE state #-}
253+ state k = lift (state k)
255+------------------------------------------------------------------------------
257+------------------------------------------------------------------------------
259+instance NFData a => NFData (Stream Identity a) where
261+ rnf (Stream xs) = runIdentity $ P.foldl' (\_ x -> rnf x) () xs
263+instance NFData1 (Stream Identity) where
264+ {-# INLINE liftRnf #-}
265+ liftRnf f (Stream xs) = runIdentity $ P.foldl' (\_ x -> f x) () xs
267+------------------------------------------------------------------------------
269+------------------------------------------------------------------------------
271+-- Serial streams can act like regular lists using the Identity monad
273+-- XXX Show instance is 10x slower compared to read, we can do much better.
274+-- The list show instance itself is really slow.
276+-- XXX The default definitions of "<" in the Ord instance etc. do not perform
277+-- well, because they do not get inlined. Need to add INLINE in Ord class in
280+instance IsList (Stream Identity a) where
281+ type (Item (Stream Identity a)) = a
283+ {-# INLINE fromList #-}
284+ fromList xs = Stream $ P.fromList xs
286+ {-# INLINE toList #-}
287+ toList (Stream xs) = runIdentity $ P.toList xs
289+instance Eq a => Eq (Stream Identity a) where
291+ (==) (Stream xs) (Stream ys) = runIdentity $ P.eqBy (==) xs ys
293+instance Ord a => Ord (Stream Identity a) where
294+ {-# INLINE compare #-}
295+ compare (Stream xs) (Stream ys) = runIdentity $ P.cmpBy compare xs ys
322+ max x y = if x <= y then y else x
325+ min x y = if x <= y then x else y
327+instance Show a => Show (Stream Identity a) where
328+ showsPrec p dl = showParen (p > 10) $
329+ showString "fromList " . shows (toList dl)
331+instance Read a => Read (Stream Identity a) where
332+ readPrec = parens $ prec 10 $ do
333+ Ident "fromList" <- lexP
334+ fromList <$> readPrec
336+ readListPrec = readListPrecDefault
338+instance (a ~ Char) => IsString (Stream Identity a) where
339+ {-# INLINE fromString #-}
340+ fromString xs = Stream $ P.fromList xs
342+-------------------------------------------------------------------------------
344+-------------------------------------------------------------------------------
346+-- The default Foldable instance has several issues:
347+-- 1) several definitions do not have INLINE on them, so we provide
348+-- re-implementations with INLINE pragmas.
349+-- 2) the definitions of sum/product/maximum/minimum are inefficient as they
350+-- use right folds, they cannot run in constant memory. We provide
351+-- implementations using strict left folds here.
353+instance (Foldable m, Monad m) => Foldable (Stream m) where
355+ {-# INLINE foldMap #-}
356+ foldMap f (Stream xs) = fold $ P.foldr (mappend . f) mempty xs
358+ {-# INLINE foldr #-}
359+ foldr f z t = appEndo (foldMap (Endo #. f) t) z
361+ {-# INLINE foldl' #-}
362+ foldl' f z0 xs = foldr f' id xs z0
363+ where f' x k = oneShot $ \z -> k $! f z x
365+ {-# INLINE length #-}
366+ length = foldl' (\n _ -> n + 1) 0
371+ {-# INLINE maximum #-}
373+ fromMaybe (errorWithoutStackTrace "maximum: empty stream")
375+ . foldl' getMax Nothing'
379+ getMax Nothing' x = Just' x
380+ getMax (Just' mx) x = Just' $! max mx x
382+ {-# INLINE minimum #-}
384+ fromMaybe (errorWithoutStackTrace "minimum: empty stream")
386+ . foldl' getMin Nothing'
390+ getMin Nothing' x = Just' x
391+ getMin (Just' mn) x = Just' $! min mn x
396+ {-# INLINE product #-}
397+ product = foldl' (*) 1
399+-------------------------------------------------------------------------------
401+-------------------------------------------------------------------------------
403+instance Traversable (Stream Identity) where
404+ {-# INLINE traverse #-}
405+ traverse f (Stream xs) =
406+ fmap Stream $ runIdentity $ P.foldr consA (pure mempty) xs
410+ consA x ys = liftA2 K.cons (f x) ys
222-------------------------------------------------------------------------------
412-------------------------------------------------------------------------------
223-- Construction
413-- Construction