streaming 0.1.2.2 → 0.1.3.0
raw patch · 4 files changed
+2774/−2028 lines, 4 filesdep +containersdep +exceptionsdep +resourcet
Dependencies added: containers, exceptions, resourcet, transformers-base
Files
- Streaming.hs +50/−26
- Streaming/Internal.hs +301/−140
- Streaming/Prelude.hs +2378/−1850
- streaming.cabal +45/−12
Streaming.hs view
@@ -4,38 +4,41 @@ -- * Free monad transformer -- $stream Stream, - -- * Constructing a 'Stream' on a base functor+ -- * Constructing a 'Stream' on a given functor unfold,- construct,- for, yields, replicates, repeats, repeatsM,- mwrap,+ effect, wrap,+ streamBuild, -- * Transforming streams decompose, maps, mapsM,+ mapped, distribute,- separate,- unseparate, groups, -- * Inspecting a stream inspect, - -- * Zipping streams- zips,+ + -- * Zipping and unzipping streams zipsWith,+ zips,+ unzips, interleaves,+ separate,+ unseparate, -- * Eliminating a 'Stream' iterTM, iterT, destroy,+ streamFold, mapsM_, run, @@ -45,19 +48,29 @@ chunksOf, concats, intercalates,- + -- period,+ -- periods,+ -- * Base functor for streams of individual items Of (..), lazily, strictly, + -- * ResourceT help + bracketStream,+ -- * re-exports MFunctor(..), MMonad(..), MonadTrans(..), MonadIO(..), Compose(..),+ MonadThrow(..),+ MonadResource(..),+ MonadBase(..),+ ResourceT(..),+ runResourceT, join, liftA2, liftA3,@@ -72,32 +85,43 @@ import Control.Monad.Trans import Data.Functor.Compose +import Control.Monad.Base+import Control.Monad.Trans.Resource {- $stream - The 'Stream' data type is equivalent to @FreeT@ and can represent any effectful- succession of steps, where the form of the steps or 'commands' is - specified by the first (functor) parameter. The present module exports- functions that pertain to that general case. So for example, if the- functor is + The 'Stream' data type can be used to represent any effectful+ succession of steps arising in some monad. + The form of the steps is specified by the first (\"functor\") + parameter in @Stream f m r@, the monad of effects by the second.+ This module exports combinators that pertain to that general case.+ Some of these are quite abstract and pervade any use of the library, + e.g. - > data Split r = Split r r+> maps :: (forall x . f x -> g x) -> Stream f m r -> Stream g m r +> mapped :: (forall x . f x -> m (g x)) -> Stream f m r -> Stream g m r +> hoist :: (forall x . m x -> n x) -> Stream f m r -> Stream f n r+> concats :: Stream (Stream f m) m r -> Stream f m r + + (assuming here and thoughout that @m@ or @n@ satisfies a @Monad@ constraint, and+ @f@ or @g@ a @Functor@ constraint.) - The @Stream Split m r@ will the type of binary trees with @r@ at the leaves- and in which each episode of branching results from an @m@-effect. - + Others are surprisingly determinate in content: +> chunksOf :: Int -> Stream f m r -> Stream (Stream f m) m r+> splits :: - In the simplest case, the base functor is @ (,) a @. Here the news - or /command/ at each step is an /individual element of type/ @ a @, - i.e. the command is a @yield@ statement. The associated - @Streaming@ 'Streaming.Prelude' - uses the left-strict pair @Of a b@ in place of the Haskell pair @(a,b)@ + One way to see that /any/ streaming library needs some such general type is+ that it is required to represent the segmentation of a stream, and to+ express the equivalents of @Prelude/Data.List@ combinators that involve+ 'lists of lists' and the like. The module @Streaming.Prelude@ exports+ combinators relating to -and operations like e.g. +> Stream (Of a) m r -> chunksOf :: Monad m => Int -> Stream f m r -> Stream (Stream f m) m r-> mapsM Streaming.Prelude.length' :: Stream (Stream (Of a) m) r -> Stream (Of Int) m r+ where @Of a r = !a :> r@ is a left-strict pair.++> mapped Streaming.Prelude.length :: Stream (Stream (Of a) m) r -> Stream (Of Int) m r -}
Streaming/Internal.hs view
@@ -1,19 +1,20 @@ {-# LANGUAGE RankNTypes, StandaloneDeriving,DeriveDataTypeable, BangPatterns #-}-{-# LANGUAGE UndecidableInstances, CPP #-} -- for show, data instances+{-# LANGUAGE UndecidableInstances, CPP, FlexibleInstances, MultiParamTypeClasses #-} module Streaming.Internal ( -- * The free monad transformer -- $stream Stream (..) -- * Introducing a stream- , construct , unfold , replicates , repeats , repeatsM- , mwrap+ , effect , wrap , yields+ , streamBuild + , cycles -- * Eliminating a stream , intercalates @@ -21,6 +22,7 @@ , iterT , iterTM , destroy + , streamFold -- * Inspecting a stream wrap by wrap , inspect @@ -28,12 +30,11 @@ -- * Transforming streams , maps , mapsM + , mapped , decompose , mapsM_ , run , distribute- , separate- , unseparate , groups -- , groupInL @@ -41,16 +42,26 @@ , chunksOf , splitsAt , takes+ -- , period+ -- , periods - -- * Zipping streams+ -- * Zipping and unzipping streams , zipsWith , zips+ , unzips , interleaves+ , separate+ , unseparate+ -- * Assorted Data.Functor.x help , switch + -- * ResourceT help+ + , bracketStream+ -- * For use in implementation , unexposed , hoistExposed@@ -74,6 +85,12 @@ import Prelude hiding (splitAt) import Data.Functor.Compose import Data.Functor.Sum+-- import Data.Time (getCurrentTime, diffUTCTime, picosecondsToDiffTime, addUTCTime)++import Control.Monad.Base+import Control.Monad.Trans.Resource+import Control.Monad.Catch (MonadCatch (..))+ {- $stream The 'Stream' data type is equivalent to @FreeT@ and can represent any effectful@@ -133,6 +150,8 @@ Step f -> Step (fmap loop f) {-# INLINABLE (>>) #-} (>>=) = _bind+ {-#INLINE (>>=) #-}+ -- stream >>= f = -- loop stream where -- loop stream0 = case stream0 of@@ -142,7 +161,8 @@ -- {-# INLINABLE (>>=) #-} fail = lift . fail-+ {-#INLINE fail #-}+ _bind :: (Functor f, Monad m)@@ -154,7 +174,8 @@ Step fstr -> Step (fmap go fstr) Effect m -> Effect (m >>= \s -> return (go s)) Return r -> f r-+{-#INLINABLE[0] _bind #-}+ {-# RULES "_bind (Step fstr) f" forall fstr f . _bind (Step fstr) f = Step (fmap (\p -> _bind p f) fstr);@@ -170,7 +191,7 @@ pure = Return {-# INLINE pure #-} streamf <*> streamx = do {f <- streamf; x <- streamx; return (f x)} - {-# INLINABLE (<*>) #-} + {-# INLINE (<*>) #-} -- stra0 *> strb = loop stra0 where -- loop stra = case stra of -- Return _ -> strb@@ -207,21 +228,47 @@ instance (MonadIO m, Functor f) => MonadIO (Stream f m) where liftIO = Effect . liftM Return . liftIO {-# INLINE liftIO #-}+ +instance (MonadBase b m, Functor f) => MonadBase b (Stream f m) where+ liftBase = effect . fmap return . liftBase+ {-#INLINE liftBase #-}+ +instance (MonadThrow m, Functor f) => MonadThrow (Stream f m) where+ throwM = lift . throwM + {-#INLINE throwM #-}+ +instance (MonadCatch m, Functor f) => MonadCatch (Stream f m) where+ catch str f = go str+ where+ go p = case p of+ Step f -> Step (fmap go f)+ Return r -> Return r+ Effect m -> Effect (catch (do+ p' <- m+ return (go p')) + (\e -> return (f e)) )+ {-#INLINABLE catch #-}+ +instance (MonadResource m, Functor f) => MonadResource (Stream f m) where+ liftResourceT = lift . liftResourceT+ {-#INLINE liftResourceT #-}+ +bracketStream :: (Functor f, MonadResource m) =>+ IO a -> (a -> IO ()) -> (a -> Stream f m b) -> Stream f m b+bracketStream alloc free inside = do+ (key, seed) <- lift (allocate alloc free)+ clean key (inside seed)+ where+ clean key = loop where+ loop str = case str of + Return r -> Effect (release key >> return (Return r))+ Effect m -> Effect (liftM loop m)+ Step f -> Step (fmap loop f)+{-#INLINABLE bracketStream #-}+ {-| Map a stream directly to its church encoding; compare @Data.List.foldr@- It permits distinctions that should be hidden, as can be seen from- e.g. --isPure stream = destroy_ (const True) (const False) (const True)-- and similar nonsense. The crucial - constraint is that the @m x -> x@ argument is an /Eilenberg-Moore algebra/.- See Atkey "Reasoning about Stream Processing with Effects"-- The destroy exported by the safe modules is --destroy str = destroy (observe str) -} destroy :: (Functor f, Monad m) =>@@ -234,42 +281,58 @@ {-# INLINABLE destroy #-} -{-| 'destroyWith' reorders the arguments of 'destroy' to be more akin+{-| 'streamFold' reorders the arguments of 'destroy' to be more akin to @foldr@ It is more convenient to query in ghci to figure out- what kind of \'algebra\' you need to write.+ what kind of \'algebra\' you need to write. ->>> :t destroyWith join return+>>> :t streamFold return join (Monad m, Functor f) => (f (m a) -> m a) -> Stream f m a -> m a -- iterT->>> :t destroyWith (join . lift) return++>>> :t streamFold return (join . lift) (Monad m, Monad (t m), Functor f, MonadTrans t) => (f (t m a) -> t m a) -> Stream f m a -> t m a -- iterTM->>> :t destroyWith effect return-(Monad m, Functor f, Functor f1) =>- (f (Stream f1 m r) -> Stream f1 m r) -> Stream f m r -> Stream f1 m r->>> :t destroyWith effect return (wrap . lazily)-Monad m => - Stream (Of a) m r -> Stream ((,) a) m r->>> :t destroyWith effect return (wrap . strictly)-Monad m => - Stream ((,) a) m r -> Stream (Of a) m r->>> :t destroyWith Data.ByteString.Streaming.effect return ++>>> :t streamFold return effect +(Monad m, Functor f, Functor g) =>+ (f (Stream g m r) -> Stream g m r) -> Stream f m r -> Stream g m r++>>> :t \f -> streamFold return effect (wrap . f)+(Monad m, Functor f, Functor g) =>+ (f (Stream g m a) -> g (Stream g m a))+ -> Stream f m a -> Stream g m a -- maps++>>> :t \f -> streamFold return effect (effect . liftM wrap . f)+(Monad m, Functor f, Functor g) =>+ (f (Stream g m a) -> m (g (Stream g m a)))+ -> Stream f m a -> Stream g m a -- mapped++ So for example, when we realize that++>>> :t streamFold return Q.mwrap (Monad m, Functor f) =>- (f (ByteString m r) -> ByteString m r) -> Stream f m r -> ByteString m r->>> :t destroyWith Data.ByteString.Streaming.effect return (\(a:>b) -> consChunk a b) -Monad m => - Stream (Of B.ByteString) m r -> ByteString m r -- fromChunks+ (f (Q.ByteString m a) -> Q.ByteString m a)+ -> Stream f m a -> Q.ByteString m a++ it is easy to see how to write @fromChunks@:++>>> streamFold return Q.mwrap (\(a:>b) -> Q.chunk a >> b)+Monad m => Stream (Of B.ByteString) m a -> Q.ByteString m a -- fromChunks -}-destroyWith+streamFold :: (Functor f, Monad m) =>- (m b -> b) -> (r -> b) -> (f b -> b) -> Stream f m r -> b-destroyWith effect done construct stream = destroy stream construct effect done+ (r -> b) -> (m b -> b) -> (f b -> b) -> Stream f m r -> b+streamFold done effect construct stream = destroy stream construct effect done+{-#INLINE streamFold #-} --- | Reflect a church-encoded stream; cp. @GHC.Exts.build@-construct+{- | Reflect a church-encoded stream; cp. @GHC.Exts.build@++> destroy a b c (streamBuild psi) = +-}+streamBuild :: (forall b . (f b -> b) -> (m b -> b) -> (r -> b) -> b) -> Stream f m r-construct = \phi -> phi Step Effect Return-{-# INLINE construct #-}+streamBuild = \phi -> phi Step Effect Return+{-# INLINE streamBuild #-} {-| Inspect the first stage of a freely layered sequence. @@ -296,9 +359,9 @@ > unfold (curry (:>) . Pipes.next) :: Monad m => Producer a m r -> Stream (Of a) m r -}- unfold :: (Monad m, Functor f) - => (s -> m (Either r (f s))) -> s -> Stream f m r+ => (s -> m (Either r (f s))) + -> s -> Stream f m r unfold step = loop where loop s0 = Effect $ do e <- step s0@@ -308,7 +371,13 @@ {-# INLINABLE unfold #-} --- | Map layers of one functor to another with a transformation+{- | Map layers of one functor to another with a transformation. Compare+ hoist, which has a similar effect on the 'monadic' parameter. ++> maps id = id+> maps f . maps g = maps (f . g)++-} maps :: (Monad m, Functor f) => (forall x . f x -> g x) -> Stream f m r -> Stream g m r maps phi = loop where@@ -319,27 +388,6 @@ {-# INLINABLE maps #-} ----- newtype NT g f = NT {runNT :: forall x . f x -> g x}--- newtype NTM g m f = NTM {runNTM :: forall x . f x -> m (g x)}--- compNTNT :: NT f g -> NT g h -> NT f h--- compNTNT (NT f) (NT g) = NT (f . g)--- compNTNTM :: Monad m => NT f g -> NTM g m h -> NTM f m h--- compNTNTM (NT f) (NTM g) = NTM (liftM f . g)--- compNTMNT :: Monad m => NTM f m g -> NT g h -> NTM f m h--- compNTMNT (NTM f) (NT g) = NTM (f . g)--- compNTMNTM :: Monad m => NTM f m g -> NTM g m h -> NTM f m h--- compNTMNTM (NTM f) (NTM g) = NTM (f <=< g)------ {-# NOINLINE [0] mapsNT #-}--- mapsNT :: (Functor f, Functor g, Monad m) => NT g f -> Stream f m r -> Stream g m r--- mapsNT (NT phi) = loop where--- loop stream = case stream of--- Return r -> Return r--- Effect m -> Effect (liftM loop m)--- Step f -> Step (phi (fmap loop f))- {- | Map layers of one functor to another with a transformation involving the base monad @maps@ is more fundamental than @mapsM@, which is best understood as a convenience for effecting this frequent composition:@@ -354,6 +402,26 @@ Step f -> Effect (liftM Step (phi (fmap loop f))) {-# INLINABLE mapsM #-} +{- | Map layers of one functor to another with a transformation involving the base monad+ @maps@ is more fundamental than @mapped@, which is best understood as a convenience+ for effecting this frequent composition:++> mapped = mapsM +> mapsM phi = decompose . maps (Compose . phi) ++ @mapped@ obeys these rules:++> mapped return = id+> mapped f . mapped g = mapped (f <=< g)+> map f . mapped g = mapped (liftM f . g)+> mapped f . map g = mapped (f . g)++-}++mapped :: (Monad m, Functor f) => (forall x . f x -> m (g x)) -> Stream f m r -> Stream g m r+mapped = mapsM+{-#INLINE mapped #-}+ {-| Resort a succession of layers of the form @m (f x)@. Though @mapsM@ is best understood as: @@ -385,11 +453,11 @@ {-# INLINABLE run #-} -{-| Map each layer to an effect in the base monad, and run them all.+{-| Map each layer to an effect, and run them all. -} mapsM_ :: (Functor f, Monad m) => (forall x . f x -> m x) -> Stream f m r -> m r-mapsM_ f str = run (maps f str)-{-# INLINABLE mapsM_ #-}+mapsM_ f = run . maps f +{-# INLINE mapsM_ #-} {-| Interpolate a layer at each segment. This specializes to e.g.@@ -397,7 +465,7 @@ > intercalates :: (Monad m, Functor f) => Stream f m () -> Stream (Stream f m) m r -> Stream f m r -} intercalates :: (Monad m, Monad (t m), MonadTrans t) =>- t m a -> Stream (t m) m b -> t m b+ t m x -> Stream (t m) m r -> t m r intercalates sep = go0 where go0 f = case f of @@ -415,9 +483,9 @@ go1 f' {-# INLINABLE intercalates #-} -{-| Specialized fold+{-| Specialized fold following the usage of @Control.Monad.Trans.Free@ -> iterTM alg stream = destroy stream alg (join . lift) return+> iterTM alg = streamFold return (join . lift) -} iterTM :: (Functor f, Monad m, MonadTrans t,@@ -426,9 +494,9 @@ iterTM out stream = destroyExposed stream out (join . lift) return {-# INLINE iterTM #-} -{-| Specialized fold+{-| Specialized fold following the usage of @Control.Monad.Trans.Free@ -> iterT alg stream = destroy stream alg join return+> iterT alg = streamFold return join alg -} iterT :: (Functor f, Monad m) => (f (m a) -> m a) -> Stream f m a -> m a@@ -437,18 +505,6 @@ {-| Dissolves the segmentation into layers of @Stream f m@ layers. -> concats stream = destroy stream join (join . lift) return-->>> S.print $ concats $ maps (cons 1776) $ chunksOf 2 (each [1..5])-1776-1-2-1776-3-4-1776-5- -} concats :: (Monad m, Functor f) => Stream (Stream f m) m r -> Stream f m r concats = loop where@@ -466,6 +522,20 @@ >>> S.print rest 2 3++> splitAt 0 = return+> splitAt n >=> splitAt m = splitAt (m+n)++ Thus, e.g. ++>>> rest <- S.print $ splitsAt 2 >=> splitsAt 2 $ each [1..5]+1+2+3+4+>>> S.print rest+5+ -} splitsAt :: (Monad m, Functor f) => Int -> Stream f m r -> Stream f m (Stream f m r) splitsAt = loop where@@ -478,15 +548,40 @@ 0 -> Return (Step fs) _ -> Step (fmap (loop (n-1)) fs) {-# INLINABLE splitsAt #-} - ++{- Functor-general take. ++ @takes 3@ can take three individual values++>>> S.print $ takes 3 $ each [1..]+1+2+3+++ or three sub-streams++>>> S.print $ mapped S.toList $ takes 3 $ chunksOf 2 $ each [1..]+[1,2]+[3,4]+[5,6]++ Or, using 'Data.ByteString.Streaming.Char' (here called @Q@),+ three byte streams.++>>> Q.stdout $ Q.unlines $ takes 3 $ Q.lines $ Q.chunk "a\nb\nc\nd\ne\nf"+a+b+c++-} takes :: (Monad m, Functor f) => Int -> Stream f m r -> Stream f m () takes n = void . splitsAt n {-# INLINE takes #-} {-| Break a stream into substreams each with n functorial layers. ->>> S.print $ maps' sum' $ chunksOf 2 $ each [1,1,1,1,1,1,1]-2+>>> S.print $ mapped S.sum $ chunksOf 2 $ each [1,1,1,1,1] 2 2 1@@ -494,9 +589,9 @@ chunksOf :: (Monad m, Functor f) => Int -> Stream f m r -> Stream (Stream f m) m r chunksOf n0 = loop where loop stream = case stream of- Return r -> Return r- Effect m -> Effect (liftM loop m)- Step fs -> Step $ Step $ fmap (fmap loop . splitsAt (n0-1)) fs+ Return r -> Return r+ Effect m -> Effect (liftM loop m)+ Step fs -> Step (Step (fmap (fmap loop . splitsAt (n0-1)) fs)) {-# INLINABLE chunksOf #-} {- | Make it possible to \'run\' the underlying transformed monad. @@ -529,12 +624,7 @@ > cycles = forever ->>> S.print $ S.take 3 $ forever $ S.each "hi"-'h'-'i'-'h'-> S.sum $ S.take 13 $ forever $ S.each [1..3]-25+>>> -} cycles :: (Monad m, Functor f) => Stream f m () -> Stream f m r@@ -598,11 +688,13 @@ -mwrap :: (Monad m, Functor f ) => m (Stream f m r) -> Stream f m r-mwrap = Effect+effect :: (Monad m, Functor f ) => m (Stream f m r) -> Stream f m r+effect = Effect+{-#INLINE effect #-} wrap :: (Monad m, Functor f ) => f (Stream f m r) -> Stream f m r wrap = Step+{-#INLINE wrap #-} {-| Lift for items in the base functor. Makes a singleton or@@ -614,6 +706,7 @@ yields :: (Monad m, Functor f) => f r -> Stream f m r yields fr = Step (fmap Return fr)+{-#INLINE yields #-} zipsWith :: (Monad m, Functor h) @@ -678,49 +771,34 @@ with the streaming on the other functor as the governing monad. This is useful for acting on one or the other functor with a fold. ->>> let odd_even = S.maps (S.distinguish even) $ S.each [1..10]->>> :t S.effects $ separate odd_even+>>> let odd_even = S.maps (S.distinguish even) $ S.each [1..10::Int]+>>> :t separate odd_even+separate odd_even+ :: Monad m => Stream (Of Int) (Stream (Of Int) m) () Now, for example, it is convenient to fold on the left and right values separately: ->>> toListM' $ toList' (separate odd_even)+>>> toList $ toList $ separate odd_even [2,4,6,8,10] :> ([1,3,5,7,9] :> ())->>> S.toListM' $ S.print $ separate $ odd_even-1-3-5-7-9-[2,4,6,8,10] :> ()- - We can easily use this device in place of filter:- -> filter = S.effects . separate . maps (distinguish f)- ->>> :t hoist S.effects $ separate odd_even-hoist S.effects $ separate odd_even :: Monad n => Stream (Of Int) n ()->>> S.print $ effects $ separate odd_even-2-4-6-8-10->>> S.print $ hoist effects $ separate odd_even-1-3-5-7-9 + We can achieve the above effect more simply+ in the case of @Stream (Of a) m r@ by using 'Streaming.Prelude.duplicate'++>>> S.toList . S.filter even $ S.toList . S.filter odd $ S.duplicate $ each [1..10::Int]+[2,4,6,8,10] :> ([1,3,5,7,9] :> ())+++ But 'separate' and 'unseparate' are functor-general. + -} separate :: (Monad m, Functor f, Functor g) => Stream (Sum f g) m r -> Stream f (Stream g m) r separate str = destroyExposed str - (\x -> case x of InL fss -> wrap fss; InR gss -> mwrap (yields gss))- (mwrap . lift) + (\x -> case x of InL fss -> wrap fss; InR gss -> effect (yields gss))+ (effect . lift) return -{-#INLINE separate #-}+{-#INLINABLE separate #-} unseparate :: (Monad m, Functor f, Functor g) => Stream f (Stream g m) r -> Stream (Sum f g) m r unseparate str = destroyExposed @@ -728,11 +806,20 @@ (wrap . InL) (join . maps InR) return -{-#INLINE unseparate #-}- +{-#INLINABLE unseparate #-}+++unzips :: (Monad m, Functor f, Functor g) => + Stream (Compose f g) m r -> Stream f (Stream g m) r +unzips str = destroyExposed+ str + (\(Compose fgstr) -> Step (fmap (Effect . yields) fgstr))+ (Effect . lift) + return +{-#INLINABLE unzips #-}+ {-| Group layers in an alternating stream into adjoining sub-streams of one type or another. -= -} groups :: (Monad m, Functor f, Functor g) => Stream (Sum f g) m r @@ -767,7 +854,8 @@ Left r -> return (return r) Right (InL fstr) -> return (wrap (InL fstr)) Right (InR gstr) -> wrap (fmap loop gstr)-+{-#INLINABLE groups #-}+ -- groupInL :: (Monad m, Functor f, Functor g) -- => Stream (Sum f g) m r -- -> Stream (Sum (Stream f m) g) m r@@ -789,3 +877,76 @@ -- Left r -> return (return r) -- Right (InL fstr) -> wrap (fmap loop fstr) -- Right (InR gstr) -> return (wrap (InR gstr))++-- {-| Permit streamed actions to proceed unless the clock has run out.+--+-- -}+-- period :: (MonadIO m, Functor f) => Double -> Stream f m r -> Stream f m (Stream f m r)+-- period seconds str = do+-- utc <- liftIO getCurrentTime+-- let loop s = do+-- utc' <- liftIO getCurrentTime+-- if diffUTCTime utc' utc > (cutoff / 1000000000)+-- then return s+-- else case s of+-- Return r -> Return (Return r)+-- Effect m -> Effect (liftM loop m)+-- Step f -> Step (fmap loop f)+-- loop str+-- where+-- cutoff = fromInteger (truncate (1000000000 * seconds))+-- {-#INLINABLE period #-}+--+--+-- {-| Divide a succession of phases according to a specified time interval. If time runs out+-- while an action is proceeding, it is allowed to run to completion. The clock is only then+-- restarted.+-- -}+-- periods :: (MonadIO m, Functor f) => Double -> Stream f m r -> Stream (Stream f m) m r+-- periods seconds s = do+-- utc <- liftIO getCurrentTime+-- loop (addUTCTime cutoff utc) s+--+-- where+-- cutoff = fromInteger (truncate (1000000000 * seconds)) / 1000000000+-- loop final stream = do+-- utc <- liftIO getCurrentTime+-- if utc > final+-- then loop (addUTCTime cutoff utc) stream+-- else case stream of+-- Return r -> Return r+-- Effect m -> Effect $ liftM (loop final) m+-- Step fstr -> Step $ fmap (periods seconds) (cutoff_ final (Step fstr))+--+-- -- do+-- -- let sloop s = do+-- -- utc' <- liftIO getCurrentTime+-- -- if final < utc'+-- -- then return s+-- -- else case s of+-- -- Return r -> Return (Return r)+-- -- Effect m -> Effect (liftM sloop m)+-- -- Step f -> Step (fmap sloop f)+-- -- Step (Step (fmap (fmap (periods seconds) . sloop) fstr))+-- -- str <- m+-- -- utc' <- liftIO getCurrentTime+-- -- if diffUTCTime utc' utc > (cutoff / 1000000000)+-- -- then return (loop utc' str)+-- -- else return (loop utc str)+-- -- Step fs -> do+-- -- let check str = do+-- -- utc' <- liftIO getCurrentTime+-- -- loop utc' str+-- --+-- {-# INLINABLE periods #-}+--+-- cutoff_ final str = do+-- let loop s = do+-- utc' <- liftIO getCurrentTime+-- if utc' > final+-- then Return s+-- else case s of+-- Return r -> Return (Return r)+-- Effect m -> Effect (liftM loop m)+-- Step f -> Step (fmap loop f)+-- loop str
Streaming/Prelude.hs view
@@ -1,1850 +1,2378 @@-{-| This module is very closely modeled on Pipes.Prelude; it attempts to - simplify and optimize the conception of Producer manipulation contained- in Pipes.Group, Pipes.Parse and the like. This is very simple and unmysterious;- it is independent of piping and conduiting, and can be used with any - rational \"streaming IO\" system. -- Import qualified thus:--> import Streaming-> import qualified Streaming.Prelude as S-- For the examples below, one sometimes needs--> import Streaming.Prelude (each, yield, stdoutLn, stdinLn)-- Other libraries that come up in passing are--> import qualified Control.Foldl as L -- cabal install foldl-> import qualified Pipes as P-> import qualified Pipes.Prelude as P-> import qualified System.IO as IO-- Here are some correspondences between the types employed here and elsewhere:--> streaming | pipes | conduit | io-streams-> --------------------------------------------------------------------------------------------------------------------> Stream (Of a) m () | Producer a m () | Source m a | InputStream a-> | ListT m a | ConduitM () o m () | Generator r ()-> --------------------------------------------------------------------------------------------------------------------> Stream (Of a) m r | Producer a m r | ConduitM () o m r | Generator a r-> --------------------------------------------------------------------------------------------------------------------> Stream (Of a) m (Stream (Of a) m r) | Producer a m (Producer a m r) | -> ---------------------------------------------------------------------------------------------------------------------> Stream (Stream (Of a) m) r | FreeT (Producer a m) m r |-> ---------------------------------------------------------------------------------------------------------------------> ---------------------------------------------------------------------------------------------------------------------> ByteString m () | Producer ByteString m () | Source m ByteString | InputStream ByteString-> ---------------------------------------------------------------------------------------------------------------------> --}-{-# LANGUAGE RankNTypes, BangPatterns, DeriveDataTypeable, TypeFamilies,- DeriveFoldable, DeriveFunctor, DeriveTraversable #-}- -module Streaming.Prelude (- -- * Types- Of (..)-- -- * Introducing streams of elements- -- $producers- , yield- , each- , unfoldr- , stdinLn- , readLn- , fromHandle- , iterate- , repeat- , replicate- , cycle- , repeatM- , replicateM- , enumFrom- , enumFromThen- - -- * Consuming streams of elements- -- $consumers- , stdoutLn- , stdoutLn'- , mapM_- , print- , toHandle- , effects- , drained-- -- * Stream transformers- -- $pipes- , map- , mapM- , chain- , maps- , sequence- , mapFoldable- , filter- , filterM- , for- , delay- , take- , takeWhile--- , takeWhile'- , drop- , dropWhile- , concat- -- , elemIndices- -- , findIndices- , scan- , scanM- , scanned- , read- , show- , cons- , duplicate-- -- * Splitting and inspecting streams of elements- , next- , uncons- , splitAt- , split- , breaks- , break- , breakWhen- , span- , group- , groupBy- , groupedBy- , timed- -- , split- -- -- * Sum and Compose manipulation- - , distinguish - , switch- , separate- , unseparate- , eitherToSum- , sumToCompose- , composeToSum- - -- * Folds- -- $folds- , fold- , fold_- , foldM- , foldM_- , sum- , sum_- , product- , product_- , length- , length_- , toList- , toList_- , mconcat- , mconcat_- , foldrM- , foldrT- - - -- , all- -- , any- -- , and- -- , or- -- , elem- -- , notElem- -- , find- -- , findIndex- -- , head- -- , index- -- , last- -- , length- -- , maximum- -- , minimum- -- , null-- -- * Zips- , zip- , zipWith- , zip3- , zipWith3- - -- * Pair manipulation- , lazily- , strictly- , fst'- , snd'- - -- * Interoperation- , reread- - -- * Basic Type- , Stream-- ) where-import Streaming.Internal--import Control.Monad hiding (filterM, mapM, mapM_, foldM, foldM_, replicateM, sequence)-import Data.Data ( Data, Typeable )-import Data.Functor.Identity-import Data.Functor.Sum-import Control.Monad.Trans-import Control.Applicative (Applicative (..))-import Data.Functor (Functor (..), (<$))--import qualified Prelude as Prelude -import Data.Foldable (Foldable)-import Data.Traversable (Traversable)-import qualified Data.Foldable as Foldable-import Text.Read (readMaybe)-import Prelude hiding (map, mapM, mapM_, filter, drop, dropWhile, take, mconcat, sum, product- , iterate, repeat, cycle, replicate, splitAt- , takeWhile, enumFrom, enumFromTo, enumFromThen, length- , print, zipWith, zip, zipWith3, zip3, seq, show, read- , readLn, sequence, concat, span, break)--import qualified GHC.IO.Exception as G-import qualified System.IO as IO-import Foreign.C.Error (Errno(Errno), ePIPE)-import Control.Exception (throwIO, try)-import Data.Monoid (Monoid (mappend, mempty))-import Data.String (IsString (..))-import Control.Concurrent (threadDelay)-import Data.Time (getCurrentTime, diffUTCTime, picosecondsToDiffTime)-import Data.Functor.Classes-import Data.Functor.Compose--- | A left-strict pair; the base functor for streams of individual elements.-data Of a b = !a :> b- deriving (Data, Eq, Foldable, Ord,- Read, Show, Traversable, Typeable)-infixr 5 :>--instance (Monoid a, Monoid b) => Monoid (Of a b) where- mempty = mempty :> mempty- {-#INLINE mempty #-}- mappend (m :> w) (m' :> w') = mappend m m' :> mappend w w'- {-#INLINE mappend #-}--instance Functor (Of a) where- fmap f (a :> x) = a :> f x- {-#INLINE fmap #-}- a <$ (b :> x) = b :> a- {-#INLINE (<$) #-}--instance Monoid a => Applicative (Of a) where- pure x = mempty :> x- {-#INLINE pure #-}- m :> f <*> m' :> x = mappend m m' :> f x- {-#INLINE (<*>) #-}- m :> x *> m' :> y = mappend m m' :> y- {-#INLINE (*>) #-}- m :> x <* m' :> y = mappend m m' :> x - {-#INLINE (<*) #-}--instance Monoid a => Monad (Of a) where- return x = mempty :> x- {-#INLINE return #-}- m :> x >> m' :> y = mappend m m' :> y- {-#INLINE (>>) #-}- m :> x >>= f = let m' :> y = f x in mappend m m' :> y- {-#INLINE (>>=) #-}--instance (r ~ (), Monad m, f ~ Of Char) => IsString (Stream f m r) where- fromString = each--instance (Eq a) => Eq1 (Of a) where eq1 = (==)-instance (Ord a) => Ord1 (Of a) where compare1 = compare-instance (Read a) => Read1 (Of a) where readsPrec1 = readsPrec-instance (Show a) => Show1 (Of a) where showsPrec1 = showsPrec--{-| Note that 'lazily', 'strictly', 'fst'', and 'mapOf' are all so-called /natural transformations/ on the primitive @Of a@ functor- If we write - -> type f ~~> g = forall x . f x -> g x- - then we can restate some types as follows:- -> mapOf :: (a -> b) -> Of a ~~> Of b -- bifunctor lmap-> lazily :: Of a ~~> (,) a-> Identity . fst' :: Of a ~~> Identity a-- Manipulation of a @Stream f m r@ by mapping often turns on recognizing natural transformations of @f@,- thus @maps@ is far more general the the @map@ of the present module, which can be- defined thus:--> S.map :: (a -> b) -> Stream (Of a) m r -> Stream (Of b) m r-> S.map f = maps (mapOf f)- - This rests on recognizing that @mapOf@ is a natural transformation; note though- that it results in such a transformation as well:- -> S.map :: (a -> b) -> Stream (Of a) m ~> Stream (Of b) m ---}-lazily :: Of a b -> (a,b)-lazily = \(a:>b) -> (a,b)-{-# INLINE lazily #-}--strictly :: (a,b) -> Of a b-strictly = \(a,b) -> a :> b-{-# INLINE strictly #-}--fst' :: Of a b -> a-fst' (a :> b) = a--snd' :: Of a b -> b-snd' (a :> b) = b--mapOf :: (a -> b) -> Of a r -> Of b r-mapOf f (a:> b) = (f a :> b)--{-| Break a sequence when a element falls under a predicate, keeping the rest of- the stream as the return value.-->>> rest <- S.print $ S.break even $ each [1,1,2,3]-1-1->>> S.print rest-2-3----}--break :: Monad m => (a -> Bool) -> Stream (Of a) m r - -> Stream (Of a) m (Stream (Of a) m r)-break pred = loop where- loop str = case str of - Return r -> Return (Return r)- Effect m -> Effect $ liftM loop m- Step (a :> rest) -> if (pred a) - then Return (Step (a :> rest))- else Step (a :> loop rest)-{-# INLINEABLE break #-}--{-| Yield elements, using a fold to maintain state, until the accumulated - value satifies the supplied predicate. The fold will then be short-circuited - and the element that breaks it will be included with the stream returned.- This function is easiest to use with 'Control.Foldl.purely'-->>> rest <- S.print $ L.purely S.breakWhen L.sum even $ S.each [1,2,3,4]-1-2->>> S.print rest-3-4---}-breakWhen :: Monad m => (x -> a -> x) -> x -> (x -> b) -> (b -> Bool) -> Stream (Of a) m r -> Stream (Of a) m (Stream (Of a) m r)-breakWhen step begin done pred = loop0 begin- where- loop0 x stream = case stream of - Return r -> return (return r)- Effect mn -> Effect $ liftM (loop0 x) mn- Step (a :> rest) -> loop a (step x a) rest- loop a !x stream = do- if pred (done x) - then return (yield a >> stream) - else case stream of - Return r -> yield a >> return (return r)- Effect mn -> Effect $ liftM (loop a x) mn- Step (a' :> rest) -> do- yield a- loop a' (step x a') rest-{-# INLINABLE breakWhen #-}--{- Break during periods where the predicate is not satisfied, grouping the periods when it is. -->>> S.print $ mapsM S.toList $ S.breaks not $ S.each [False,True,True,False,True,True,False]-[True,True]-[True,True]->>> S.print $ mapsM S.toList $ S.breaks id $ S.each [False,True,True,False,True,True,False]-[False]-[False]-[False]--}-breaks- :: Monad m =>- (a -> Bool) -> Stream (Of a) m r -> Stream (Stream (Of a) m) m r-breaks thus = loop where- loop stream = Effect $ do- e <- next stream- return $ case e of- Left r -> Return r- Right (a, p') -> - if not (thus a)- then Step $ fmap loop (yield a >> break thus p')- else loop p'-{-#INLINABLE breaks #-}- --{-| Apply an action to all values flowing downstream--->>> S.product (S.chain Prelude.print (S.each [2..4])) >>= Prelude.print-2-3-4f-24 :> ()---}--chain :: Monad m => (a -> m ()) -> Stream (Of a) m r -> Stream (Of a) m r-chain f = loop where - loop str = case str of - Return r -> return r- Effect mn -> Effect (liftM loop mn)- Step (a :> rest) -> Effect $ do- f a- return (Step (a :> loop rest))-{-# INLINE chain #-}--{-| Make a stream of traversable containers into a stream of their separate elements.- This is just --> concat = for str each-->>> S.print $ S.concat (each ["xy","z"])-'x'-'y'-'z'-- Note that it also has the effect of 'Data.Maybe.catMaybes' and 'Data.Either.rights'--->>> S.print $ S.concat $ S.each [Just 1, Nothing, Just 2]-1-2->>> S.print $ S.concat $ S.each [Right 1, Left "Error!", Right 2]-1-2-- @concat@ is not to be confused with the functor-general --> concats :: (Monad m, Functor f) => Stream (Stream f m) m r -> Stream f m r -- specializing-->>> S.stdoutLn $ concats $ maps (<* yield "--\n--") $ chunksOf 2 $ S.show (each [1..5])-1-2-------3-4-------5--------}--concat :: (Monad m, Foldable.Foldable f) => Stream (Of (f a)) m r -> Stream (Of a) m r-concat str = for str each-{-# INLINE concat #-}--{-| The natural @cons@ for a @Stream (Of a)@. --> cons a stream = yield a >> stream-- Useful for interoperation:--> Data.Text.foldr S.cons (return ()) :: Text -> Stream (Of Char) m ()-> Lazy.foldrChunks S.cons (return ()) :: Lazy.ByteString -> Stream (Of Strict.ByteString) m ()-- and so on.--}--cons :: (Monad m) => a -> Stream (Of a) m r -> Stream (Of a) m r-cons a str = Step (a :> str)-{-# INLINE cons #-}--{- | Cycle repeatedly through the layers of a stream, /ad inf./ This- function is functor-general--> cycle = forever-->>> rest <- S.print $ S.splitAt 3 $ S.cycle (yield True >> yield False)-True-False-True->>> S.print $ S.take 3 rest-False-True-False---}--cycle :: (Monad m, Functor f) => Stream f m r -> Stream f m s-cycle = forever---{-| Effect each element by the supplied number of seconds.-mapM :: Monad m => (a -> m b) -> Stream (Of a) m r -> Stream (Of b) m r---}-delay :: MonadIO m => Double -> Stream (Of a) m r -> Stream (Of a) m r-delay seconds = mapM go where- go a = liftIO (threadDelay (truncate (seconds * 1000000))) >> return a--- ------------------ effects--- -----------------{- | Reduce a stream, performing its actions but ignoring its elements. - This might just be called @effects@ or @runEffects@.-->>> let effect = lift (putStrLn "Effect!")->>> let stream = do {yield 1; effect; yield 2; effect; return (2^100)} -->>> S.effects stream-Effect!-Effect!-1267650600228229401496703205376-->>> S.effects $ S.takeWhile (<2) stream-Effect!---}-effects :: Monad m => Stream (Of a) m r -> m r-effects = loop where- loop stream = case stream of - Return r -> return r- Effect m -> m >>= loop - Step (_ :> rest) -> loop rest-{-#INLINABLE effects #-}- -{-| Where a transformer returns a stream, run the effects of the stream, keeping- the return value. This is usually used at the type--> drained :: Monad m => Stream (Of a) m (Stream (Of b) m r) -> Stream (Of a) m r--> drained = join . fmap (lift . effects)-->>> let take' n = S.drained . S.splitAt n->>> S.print $ concats $ maps (take' 1) $ S.group $ S.each "wwwwarrrrr"-'w'-'a'-'r'-- --}-drained :: (Monad m, Monad (t m), Functor (t m), MonadTrans t) => t m (Stream (Of a) m r) -> t m r-drained = join . fmap (lift . effects)-{-#INLINE drained #-}---- ------------------ drop--- ------------------- | Ignore the first n elements of a stream, but carry out the actions-drop :: (Monad m) => Int -> Stream (Of a) m r -> Stream (Of a) m r-drop = loop where- loop 0 stream = stream- loop n stream = case stream of- Return r -> Return r- Effect ma -> Effect (liftM (loop n) ma)- Step (a :> as) -> loop (n-1) as-{-# INLINE drop #-}---- ------------------ dropWhile--- -----------------{- | Ignore elements of a stream until a test succeeds.-->>> IO.withFile "distribute.hs" IO.ReadMode $ S.stdoutLn . S.take 2 . S.dropWhile (isPrefixOf "import") . S.fromHandle-main :: IO ()-main = do----}-dropWhile :: Monad m => (a -> Bool) -> Stream (Of a) m r -> Stream (Of a) m r-dropWhile pred = loop where - loop stream = case stream of- Return r -> Return r- Effect ma -> Effect (liftM loop ma)- Step (a :> as) -> if pred a - then loop as- else Step (a :> as)-{-# INLINE dropWhile #-}---- ------------------ each --- -----------------{- | Stream the elements of a foldable container.-->>> S.print $ S.map (*100) $ each [1..3] -100-200-300-->>> S.print $ S.map (*100) $ each [1..3] >> lift readLn >>= yield-100-200-300-4<Enter>-400--}-each :: (Monad m, Foldable.Foldable f) => f a -> Stream (Of a) m ()-each = Foldable.foldr (\a p -> Step (a :> p)) (Return ())-{-# INLINE each #-}---- -------- enumFrom--- --------{-| An infinite stream of enumerable values, starting from a given value.- @Streaming.Prelude.enumFrom@ is more desirable that @each [x..]@ for - the infinite case, because it has a polymorphic return type.- ->>> S.print $ S.take 3 $ S.enumFrom 'a'-'a'-'b'-'c'-- Because their return type is polymorphic, @enumFrom@ and @enumFromThen@- are useful for example with @zip@- and @zipWith@, which require the same return type in the zipped streams. - With @each [1..]@ the following would be impossible.-->>> rest <- S.print $ S.zip (S.enumFrom 'a') $ S.splitAt 3 $ S.enumFrom 1-('a',1)-('b',2)-('c',3)->>> S.print $ S.take 3 rest-4-5-6-- Where a final element is specified, as in @each [1..10]@ a special combinator- is unneeded, since the return type would be @()@ anyway.---}-enumFrom :: (Monad m, Enum n) => n -> Stream (Of n) m r-enumFrom = loop where- loop !n = Step (n :> loop (succ n))-{-# INLINEABLE enumFrom #-}---{-| An infinite sequence of enumerable values at a fixed distance, determined- by the first and second values. See the discussion of 'Streaming.enumFrom'-->>> S.print $ S.take 3 $ S.enumFromThen 100 200-100-200-300---}-enumFromThen:: (Monad m, Enum a) => a -> a -> Stream (Of a) m r-enumFromThen first second = Streaming.Prelude.map toEnum (loop _first)- where- _first = fromEnum first- _second = fromEnum second- diff = _second - _first- loop !s = Step (s :> loop (s+diff))-{-# INLINEABLE enumFromThen #-}---- ------------------ filter --- ------------------- | Skip elements of a stream that fail a predicate-filter :: (Monad m) => (a -> Bool) -> Stream (Of a) m r -> Stream (Of a) m r-filter pred = loop where- loop str = case str of- Return r -> Return r- Effect m -> Effect (liftM loop m)- Step (a :> as) -> if pred a - then Step (a :> loop as)- else loop as-{-# INLINE filter #-}---- ------------------ filterM--- ------------------- | Skip elements of a stream that fail a monadic test-filterM :: (Monad m) => (a -> m Bool) -> Stream (Of a) m r -> Stream (Of a) m r-filterM pred = loop where- loop str = case str of- Return r -> Return r- Effect m -> Effect $ liftM loop m- Step (a :> as) -> Effect $ do - bool <- pred a- if bool - then return $ Step (a :> loop as)- else return $ loop as-{-# INLINEABLE filterM #-}---- ------------------ fold--- -----------------{- $folds- Use these to fold the elements of a 'Stream'. -->>> S.fold_ (+) 0 id $ S.each [1..0]-50-- The general folds 'fold', fold_', 'foldM' and 'foldM_' are arranged - for use with 'Control.Foldl'-->>> L.purely fold_ L.sum $ each [1..10]-55->>> L.purely fold_ (liftA3 (,,) L.sum L.product L.list) $ each [1..10]-(55,3628800,[1,2,3,4,5,6,7,8,9,10])-- All functions marked with an underscore omit - (e.g. @fold_@, @sum_@) the stream's return value in a left-strict pair.- They are good for exiting streaming completely, - but when you are, e.g. @mapsM@-ing over a @Stream (Stream (Of a) m) m r@, - which is to be compared with @[[a]]@. Specializing, we have e.g.--> mapsM sum :: (Monad m, Num n) => Stream (Stream (Of Int)) IO () -> Stream (Of n) IO ()-> mapsM (fold mappend mempty id) :: Stream (Stream (Of Int)) IO () -> Stream (Of Int) IO ()-->>> S.print $ mapsM S.sum $ chunksOf 3 $ S.each [1..10]-6-15-24-10-->>> let three_folds = L.purely S.fold (liftA3 (,,) L.sum L.product L.list)->>> S.print $ mapsM three_folds $ chunksOf 3 (each [1..10])-(6,6,[1,2,3])-(15,120,[4,5,6])-(24,504,[7,8,9])-(10,10,[10])--}--{-| Strict fold of a 'Stream' of elements--> Control.Foldl.purely fold :: Monad m => Fold a b -> Stream (Of a) m () -> m b--}-fold_ :: Monad m => (x -> a -> x) -> x -> (x -> b) -> Stream (Of a) m r -> m b-fold_ step begin done stream0 = loop stream0 begin- where- loop !stream !x = case stream of - Return r -> return (done x)- Effect m -> m >>= \s -> loop s x- Step (a :> rest) -> loop rest (step x a)-{-# INLINABLE fold_ #-}--{-| Strict fold of a 'Stream' of elements that preserves the return value. -->>> S.sum $ each [1..10]-55 :> ()-->>> (n :> rest) <- S.sum $ S.splitAt 3 (each [1..10])->>> print n-6->>> (m :> rest') <- S.sum $ S.splitAt 3 rest->>> print m-15->>> S.print rest'-7-8-9-- The type provides for interoperation with the foldl library.--> Control.Foldl.purely fold :: Monad m => Fold a b -> Stream (Of a) m r -> m (Of b r)-- Thus, specializing a bit:--> L.purely fold L.sum :: Stream (Of Int) Int r -> m (Of Int r)-> maps (L.purely fold L.sum) :: Stream (Stream (Of Int)) IO r -> Stream (Of Int) IO r--->>> S.print $ mapsM (L.purely S.fold (liftA2 (,) L.list L.sum)) $ chunksOf 3 $ each [1..10]-([1,2,3],6)-([4,5,6],15)-([7,8,9],24)-([10],10)--}--fold :: Monad m => (x -> a -> x) -> x -> (x -> b) -> Stream (Of a) m r -> m (Of b r)-fold step begin done s0 = loop s0 begin- where- loop stream !x = case stream of - Return r -> return (done x :> r)- Effect m -> m >>= \s -> loop s x- Step (a :> rest) -> loop rest (step x a)-{-# INLINABLE fold #-}--{-| Strict, monadic fold of the elements of a 'Stream (Of a)'--> Control.Foldl.impurely foldM :: Monad m => FoldM a b -> Stream (Of a) m () -> m b--}-foldM_- :: Monad m- => (x -> a -> m x) -> m x -> (x -> m b) -> Stream (Of a) m r -> m b-foldM_ step begin done s0 = do- x0 <- begin- loop s0 x0- where- loop stream !x = case stream of - Return r -> done x - Effect m -> m >>= \s -> loop s x- Step (a :> rest) -> do- x' <- step x a- loop rest x'-{-# INLINABLE foldM_ #-}--{-| Strict, monadic fold of the elements of a 'Stream (Of a)'--> Control.Foldl.impurely foldM' :: Monad m => FoldM a b -> Stream (Of a) m r -> m (b, r)--}-foldM- :: Monad m- => (x -> a -> m x) -> m x -> (x -> m b) -> Stream (Of a) m r ->m (Of b r)-foldM step begin done str = do- x0 <- begin- loop str x0- where- loop stream !x = case stream of - Return r -> done x >>= \b -> return (b :> r)- Effect m -> m >>= \s -> loop s x- Step (a :> rest) -> do- x' <- step x a- loop rest x'-{-# INLINABLE foldM #-}----{-| A natural right fold for consuming a stream of elements. - See also the more general 'iterTM' in the 'Streaming' module - and the still more general 'destroy'--> foldrT (\a p -> Pipes.yield a >> p) :: Monad m => Stream (Of a) m r -> Producer a m r-> foldrT (\a p -> Conduit.yield a >> p) :: Monad m => Stream (Of a) m r -> Conduit a m r---}--foldrT :: (Monad m, MonadTrans t, Monad (t m)) - => (a -> t m r -> t m r) -> Stream (Of a) m r -> t m r-foldrT step = loop where- loop stream = case stream of- Return r -> return r- Effect m -> lift m >>= loop- Step (a :> as) -> step a (loop as)-{-# INLINABLE foldrT #-} --{-| A natural right fold for consuming a stream of elements.- See also the more general 'iterT' in the 'Streaming' module and the- still more general 'destroy'--}-foldrM :: Monad m - => (a -> m r -> m r) -> Stream (Of a) m r -> m r-foldrM step = loop where- loop stream = case stream of- Return r -> return r- Effect m -> m >>= loop- Step (a :> as) -> step a (loop as)-{-# INLINABLE foldrM #-} ---- ------------------ for--- ------------------- | @for@ replaces each element of a stream with an associated stream. Note that the--- associated stream may layer any functor. -for :: (Monad m, Functor f) => Stream (Of a) m r -> (a -> Stream f m x) -> Stream f m r-for str0 act = loop str0 where- loop str = case str of- Return r -> Return r - Effect m -> Effect $ liftM loop m- Step (a :> rest) -> do- act a- loop rest-{-# INLINEABLE for #-}--{-| Group layers of any functor by comparisons on a preliminary annotation ---}-groupedBy- :: (Monad m, Functor f) =>- (a -> a -> Bool)- -> Stream (Compose (Of a) f) m r- -> Stream (Stream (Compose (Of a) f) m) m r-groupedBy equals = loop where- loop stream = Effect $ do- e <- inspect stream- return $ case e of- Left r -> Return r- Right s@(Compose (a :> p')) -> Step $- fmap loop (Step $ Compose (a :> fmap (span' (equals a)) p'))- span' :: (Monad m, Functor f) => (a -> Bool) -> Stream (Compose (Of a) f) m r- -> Stream (Compose (Of a) f) m (Stream (Compose (Of a) f) m r)- span' pred = loop where- loop str = case str of- Return r -> Return (Return r)- Effect m -> Effect $ liftM loop m- Step s@(Compose (a :> rest)) -> case pred a of- True -> Step (Compose (a :> fmap loop rest))- False -> Return (Step s)-{-# INLINEABLE groupedBy #-} --{-| Group elements of a stream by comparisons on a preliminary annotation ---}-groupBy :: Monad m - => (a -> a -> Bool)- -> Stream (Of a) m r - -> Stream (Stream (Of a) m) m r-groupBy equals = loop where- loop stream = Effect $ do- e <- next stream- return $ case e of- Left r -> Return r- Right (a, p') -> Step $- fmap loop (yield a >> span (equals a) p')- -{-# INLINEABLE groupBy #-} --group :: (Monad m, Eq a) => Stream (Of a) m r -> Stream (Stream (Of a) m) m r -group = groupBy (==)----- ------------------ iterate--- ------------------- | Iterate a pure function from a seed value, streaming the results forever-iterate :: (a -> a) -> a -> Stream (Of a) m r-iterate f = loop where- loop a' = Step (a' :> loop (f a'))-{-# INLINEABLE iterate #-}---- | Iterate a monadic function from a seed value, streaming the results forever-iterateM :: Monad m => (a -> m a) -> m a -> Stream (Of a) m r-iterateM f = loop where- loop ma = Effect $ do - a <- ma- return (Step (a :> loop (f a)))-{-# INLINEABLE iterateM #-}----- ------------------ length--- -----------------{-| Run a stream, remembering only its length:-->>> S.length $ S.each [1..10]-10---}-length_ :: Monad m => Stream (Of a) m r -> m Int-length_ = fold_ (\n _ -> n + 1) 0 id-{-#INLINE length_#-}--{-| Run a stream, keeping its length and its return value. -->>> S.print $ mapsM S.length $ chunksOf 3 $ S.each [1..10]-3-3-3-1---}--length :: Monad m => Stream (Of a) m r -> m (Of Int r)-length = fold (\n _ -> n + 1) 0 id-{-#INLINE length #-}--- ------------------ map--- ------------------- | Standard map on the elements of a stream.-map :: Monad m => (a -> b) -> Stream (Of a) m r -> Stream (Of b) m r-map f = loop where- loop stream = case stream of- Return r -> Return r- Effect m -> Effect (liftM loop m)- Step (a :> as) -> Step (f a :> loop as)-{-# INLINE map #-}---- ------------------ mapFoldable--- -----------------{-| For each element of a stream, stream a foldable container of elements instead; compare- 'Pipes.Prelude.mapFoldable'.--> mapFoldable f str = for str (\a -> each (f a))-->>> S.print $ S.mapFoldable show $ yield 12-'1'-'2'---}-mapFoldable :: (Monad m, Foldable.Foldable t) => (a -> t b) -> Stream (Of a) m r -> Stream (Of b) m r-mapFoldable f str = for str (\a -> each (f a)) -- as in pipes---- | Replace each element of a stream with the result of a monadic action-mapM :: Monad m => (a -> m b) -> Stream (Of a) m r -> Stream (Of b) m r-mapM f = loop where- loop str = case str of - Return r -> Return r - Effect m -> Effect (liftM loop m)- Step (a :> as) -> Effect $ do - a' <- f a - return (Step (a' :> loop as) )-{-# INLINEABLE mapM #-}----{-| Reduce a stream to its return value with a monadic action.-->>> mapM_ Prelude.print $ each [1..3] >> return True-1-2-3-True---}-mapM_ :: Monad m => (a -> m b) -> Stream (Of a) m r -> m r-mapM_ f = loop where- loop str = case str of - Return r -> return r - Effect m -> m >>= loop- Step (a :> as) -> do - f a - loop as -{-# INLINEABLE mapM_ #-}---mconcat :: (Monad m, Monoid w) => Stream (Of w) m r -> m (Of w r)-mconcat = fold mappend mempty id-{-#INLINE mconcat #-}--mconcat_ :: (Monad m, Monoid w) => Stream (Of w) m r -> m w-mconcat_ = fold_ mappend mempty id--{-| The standard way of inspecting the first item in a stream of elements, if the- stream is still \'running\'. The @Right@ case contains a - Haskell pair, where the more general @inspect@ would return a left-strict pair. - There is no reason to prefer @inspect@ since, if the @Right@ case is exposed, - the first element in the pair will have been evaluated to whnf.--> next :: Monad m => Stream (Of a) m r -> m (Either r (a, Stream (Of a) m r))-> inspect :: Monad m => Stream (Of a) m r -> m (Either r (Of a (Stream (Of a) m r)))-- Interoperate with @pipes@ producers thus:--> Pipes.unfoldr Stream.next :: Stream (Of a) m r -> Producer a m r-> Stream.unfoldr Pipes.next :: Producer a m r -> Stream (Of a) m r - - Similarly: --> IOStreams.unfoldM (liftM (either (const Nothing) Just) . next) :: Stream (Of a) IO b -> IO (InputStream a)-> Conduit.unfoldM (liftM (either (const Nothing) Just) . next) :: Stream (Of a) m r -> Source a m r-- But see 'uncons', which is better fitted to these @unfoldM@s--}-next :: Monad m => Stream (Of a) m r -> m (Either r (a, Stream (Of a) m r))-next = loop where- loop stream = case stream of- Return r -> return (Left r)- Effect m -> m >>= loop- Step (a :> rest) -> return (Right (a,rest))-{-# INLINABLE next #-}---{-| Inspect the first item in a stream of elements, without a return value. - @uncons@ provides convenient exit into another streaming type:--> IOStreams.unfoldM uncons :: Stream (Of a) IO b -> IO (InputStream a)-> Conduit.unfoldM uncons :: Stream (Of a) m r -> Conduit.Source m a---}-uncons :: Monad m => Stream (Of a) m () -> m (Maybe (a, Stream (Of a) m ()))-uncons = loop where- loop stream = case stream of- Return () -> return Nothing- Effect m -> m >>= loop- Step (a :> rest) -> return (Just (a,rest))-{-# INLINABLE uncons #-}----- | Fold a 'Stream' of numbers into their product-product_ :: (Monad m, Num a) => Stream (Of a) m () -> m a-product_ = fold_ (*) 1 id-{-# INLINE product_ #-}--{-| Fold a 'Stream' of numbers into their product with the return value--> maps' product' :: Stream (Stream (Of Int)) m r -> Stream (Of Int) m r--}-product :: (Monad m, Num a) => Stream (Of a) m r -> m (Of a r)-product = fold (*) 1 id-{-# INLINE product #-}----- ------------------ read--- ------------------- | Make a stream of strings into a stream of parsed values, skipping bad cases-read :: (Monad m, Read a) => Stream (Of String) m r -> Stream (Of a) m r-read stream = for stream $ \str -> case readMaybe str of - Nothing -> return ()- Just r -> yield r-{-# INLINE read #-}---- ------------------ repeat--- ----------------{-| Repeat an element /ad inf./ .-->>> S.print $ S.take 3 $ S.repeat 1-1-1-1--}--repeat :: a -> Stream (Of a) m r-repeat a = loop where loop = Step (a :> loop)-{-# INLINE repeat #-}---{-| Repeat a monadic action /ad inf./, streaming its results.-->>> S.toListM $ S.take 2 (repeatM getLine)-hello<Enter>-world<Enter>-["hello","world"]--}--repeatM :: Monad m => m a -> Stream (Of a) m r-repeatM ma = loop where- loop = do - a <- lift ma - yield a - loop-{-# INLINEABLE repeatM #-}---- ------------------ replicate --- ------------------- | Repeat an element several times-replicate :: Monad m => Int -> a -> Stream (Of a) m ()-replicate n a = loop n where- loop 0 = Return ()- loop m = Step (a :> loop (m-1))-{-# INLINEABLE replicate #-}--{-| Repeat an action several times, streaming the results.-->>> S.print $ S.replicateM 2 getCurrentTime-2015-08-18 00:57:36.124508 UTC-2015-08-18 00:57:36.124785 UTC---}-replicateM :: Monad m => Int -> m a -> Stream (Of a) m ()-replicateM n ma = loop n where - loop 0 = Return ()- loop n = Effect $ do - a <- ma - return (Step $ a :> loop (n-1))-{-# INLINEABLE replicateM #-}--{-| Read an @IORef (Maybe a)@ or a similar device until it reads @Nothing@.- @reread@ provides convenient exit from the @io-streams@ library--> reread readIORef :: IORef (Maybe a) -> Stream (Of a) IO ()-> reread Streams.read :: System.IO.Streams.InputStream a -> Stream (Of a) IO ()--}-reread :: Monad m => (s -> m (Maybe a)) -> s -> Stream (Of a) m ()-reread step s = loop where - loop = Effect $ do - m <- step s- case m of - Nothing -> return (Return ())- Just a -> return (Step (a :> loop))-{-# INLINEABLE reread #-}--{-| Strict left scan, streaming, e.g. successive partial results.--> Control.Foldl.purely scan :: Monad m => Fold a b -> Stream (Of a) m r -> Stream (Of b) m r-->>> S.print $ L.purely S.scan L.list $ each [3..5]-[]-[3]-[3,4]-[3,4,5]-- A simple way of including the scanned item with the accumulator is to use- 'Control.Foldl.last'. See also 'Streaming.Prelude.scanned'-->>> let a >< b = (,) <$> a <*> b->>> S.print $ L.purely S.scan (L.last >< L.sum) $ S.each [1..3]-(Nothing,0)-(Just 1,1)-(Just 2,3)-(Just 3,6)---}-scan :: Monad m => (x -> a -> x) -> x -> (x -> b) -> Stream (Of a) m r -> Stream (Of b) m r-scan step begin done = loop begin- where- loop !x stream = Step $ - done x :> case stream of - Return r -> Return r- Effect m -> Effect $ liftM (loop x) m- Step (a :> rest) -> do- let !x' = step x a- loop x' rest-{-# INLINE scan #-}--{-| Strict, monadic left scan--> Control.Foldl.impurely scanM :: Monad m => FoldM a m b -> Stream (Of a) m r -> Stream (Of b) m r-->>> let v = L.impurely scanM L.vector $ each [1..4::Int] :: Stream (Of (U.Vector Int)) IO ()->>> S.print v-fromList []-fromList [1]-fromList [1,2]-fromList [1,2,3]-fromList [1,2,3,4]---}-scanM :: Monad m => (x -> a -> m x) -> m x -> (x -> m b) -> Stream (Of a) m r -> Stream (Of b) m r-scanM step begin done str = do- x <- lift begin- loop x str- where- loop !x stream = do - b <- lift (done x)- yield b- case stream of - Return r -> Return r- Effect m -> Effect $ liftM (loop x) m- Step (a :> rest) -> do- x' <- lift $ step x a- loop x' rest-{-# INLINABLE scanM #-}--{- Label each element in a stream with a value accumulated according to a fold.--->>> S.print $ S.scanned (*) 1 id $ S.each [100,200,300]-(100,100)-(200,20000)-(300,6000000)-->>> S.print $ L.purely S.scanned L.product $ S.each [100,200,300]-(100,100)-(200,20000)-(300,6000000)---}--data Maybe' a = Just' a | Nothing'--scanned :: Monad m => (x -> a -> x) -> x -> (x -> b) -> Stream (Of a) m r -> Stream (Of (a,b)) m r-scanned step begin done = loop Nothing' begin- where- loop !m !x stream = do - case stream of - Return r -> return r- Effect mn -> Effect $ liftM (loop m x) mn- Step (a :> rest) -> do- case m of - Nothing' -> do - let !acc = step x a- yield (a, done acc)- loop (Just' a) acc rest- Just' _ -> do- let !acc = done (step x a)- yield (a, acc) - loop (Just' a) (step x a) rest-{-# INLINABLE scanned #-}----- ------------------ sequence--- -----------------{-| Like the 'Data.List.sequence' but streaming. The result type is a- stream of a\'s, /but is not accumulated/; the effects of the elements- of the original stream are interleaved in the resulting stream. Compare:--> sequence :: Monad m => [m a] -> m [a]-> sequence :: Monad m => Stream (Of (m a)) m r -> Stream (Of a) m r--}-sequence :: Monad m => Stream (Of (m a)) m r -> Stream (Of a) m r-sequence = loop where- loop stream = case stream of- Return r -> Return r- Effect m -> Effect $ liftM loop m- Step (ma :> rest) -> Effect $ do- a <- ma- return (Step (a :> loop rest))-{-# INLINEABLE sequence #-}---- ------------------ show--- -----------------show :: (Monad m, Show a) => Stream (Of a) m r -> Stream (Of String) m r-show = map Prelude.show-{-# INLINE show #-}--- ------------------ sum --- ------------------- | Fold a 'Stream' of numbers into their sum-sum_ :: (Monad m, Num a) => Stream (Of a) m () -> m a-sum_ = fold_ (+) 0 id-{-# INLINE sum_ #-}--{-| Fold a 'Stream' of numbers into their sum with the return value--> maps' sum' :: Stream (Stream (Of Int)) m r -> Stream (Of Int) m r--}-sum :: (Monad m, Num a) => Stream (Of a) m r -> m (Of a r)-sum = fold (+) 0 id-{-# INLINE sum #-}---- ------------------ span--- ------------------- | Stream elements until one fails the condition, return the rest.-span :: Monad m => (a -> Bool) -> Stream (Of a) m r - -> Stream (Of a) m (Stream (Of a) m r)-span pred = loop where- loop str = case str of - Return r -> Return (Return r)- Effect m -> Effect $ liftM loop m- Step (a :> rest) -> if pred a - then Step (a :> loop rest)- else Return (Step (a :> rest))-{-# INLINEABLE span #-}-- -{-| Split a stream of elements wherever a given element arises.- The action is like that of 'Prelude.words'. -->>> S.stdoutLn $ mapsM S.toList $ split ' ' "hello world " -hello-world->>> Prelude.mapM_ Prelude.putStrLn (Prelude.words "hello world ")-hello-world---}--split :: (Eq a, Monad m) =>- a -> Stream (Of a) m r -> Stream (Stream (Of a) m) m r-split t = loop where- loop stream = do- e <- lift $ next stream- case e of- Left r -> Return r- Right (a, p') -> - if a /= t- then Step $ fmap loop (yield a >> break (== t) p')- else loop p'-{-#INLINABLE split #-}--{-| Split a succession of layers after some number, returning a streaming or--- effectful pair. This function is the same as the 'splitsAt' exported by the--- @Streaming@ module, but since this module is imported qualified, it can --- usurp a Prelude name. It specializes to:--> splitAt :: (Monad m, Functor f) => Int -> Stream (Of a) m r -> Stream (Of a) m (Stream (Of a) m r)---}-splitAt :: (Monad m, Functor f) => Int -> Stream f m r -> Stream f m (Stream f m r)-splitAt = splitsAt-{-# INLINE splitAt #-}-- --- ------------------ take--- -----------------{-| End a stream after n elements; the original return value is thus lost.- 'splitAt' preserves this information. Note that, like @splitAt@, this- function is functor-general, so that, for example, you can @take@ not- just a number of items from a stream of elements, but a number - of substreams and the like.-->>> S.print $ mapsM S.sum $ S.take 2 $ chunksOf 3 $ each [1..]-6 -- sum of first group of 3-15 -- sum of second group of 3---}--take :: (Monad m, Functor f) => Int -> Stream f m r -> Stream f m ()-take = loop where- loop 0 p = return ()- loop n p = - case p of Step fas -> Step (fmap (loop (n-1)) fas)- Effect m -> Effect (liftM (loop n) m)- Return r -> Return ()-{-# INLINE take #-}---- ------------------ takeWhile--- ------------------- | End stream when an element fails a condition; the original return value is lost--- 'span' preserves this information.-takeWhile :: Monad m => (a -> Bool) -> Stream (Of a) m r -> Stream (Of a) m ()-takeWhile pred = loop where- loop str = case str of - Step (a :> as) -> when (pred a) (Step (a :> loop as))- Effect m -> Effect (liftM loop m)- Return r -> Return ()-{-# INLINE takeWhile #-}--{- Break a stream after the designated number of seconds.--->>> rest <- S.print $ S.timed 1 $ S.delay 0.3 $ S.each [1..]-1-2-3->>> S.print $ S.take 3 rest-4-5-6------}--timed :: MonadIO m => Double -> Stream (Of a) m r -> Stream (Of a) m (Stream (Of a) m r)-timed seconds str = do- utc <- liftIO getCurrentTime- loop utc str- where- cutoff = fromInteger $ truncate (1000000000 * seconds)- loop utc str = do- utc' <- liftIO getCurrentTime- if diffUTCTime utc' utc > (cutoff / 1000000000)- then return str- else case str of- Return r -> return (return r)- Effect m -> Effect (liftM (loop utc) m)- Step (a:>rest) -> yield a >> loop utc rest- ---{-| Convert an effectful 'Stream (Of a)' into a list of @as@-- Note: Needless to say this function does not stream properly.- It is basically the same as 'mapM' which, like 'replicateM',- 'sequence' and similar operations on traversable containers- is a leading cause of space leaks.- --}-toList_ :: Monad m => Stream (Of a) m () -> m [a]-toList_ = fold_ (\diff a ls -> diff (a: ls)) id (\diff -> diff [])-{-# INLINE toList_ #-}---{-| Convert an effectful 'Stream' into a list alongside the return value--> mapsM toListM :: Stream (Stream (Of a)) m r -> Stream (Of [a]) m --}-toList :: Monad m => Stream (Of a) m r -> m (Of [a] r)-toList = fold (\diff a ls -> diff (a: ls)) id (\diff -> diff [])-{-# INLINE toList #-}--{-| Build a @Stream@ by unfolding steps starting from a seed. -- The seed can of course be anything, but this is one natural way - to consume a @pipes@ 'Pipes.Producer'. Consider:-->>> S.stdoutLn $ S.take 2 (S.unfoldr P.next P.stdinLn)-hello<Enter>-hello-goodbye<Enter>-goodbye-->>> S.stdoutLn $ S.unfoldr P.next (P.stdinLn P.>-> P.take 2)-hello<Enter>-hello-goodbye<Enter>-goodbye-->>> S.effects $ S.unfoldr P.next (P.stdinLn P.>-> P.take 2 P.>-> P.stdoutLn)-hello<Enter>-hello-goodbye<Enter>-goodbye-- If the intended \"coalgebra\" is complicated it might be pleasant to - write it with the state monad:--> \state seed -> S.unfoldr (runExceptT . runStateT state) seed :: Monad m => StateT s (ExceptT r m) a -> s -> P.Producer a m r-->>> let state = do {n <- get ; if n >= 3 then lift (throwE "Got to three"); else put (n+1); return n}->>> S.print $ S.unfoldr (runExceptT . runStateT state) 0 -0-1-2-"Got to three"--}-unfoldr :: Monad m - => (s -> m (Either r (a, s))) -> s -> Stream (Of a) m r-unfoldr step = loop where- loop s0 = Effect $ do - e <- step s0- case e of- Left r -> return (Return r)- Right (a,s) -> return (Step (a :> loop s))-{-# INLINABLE unfoldr #-}---- ------------------------------------------ yield--- -----------------------------------------{-| A singleton stream-->>> stdoutLn $ yield "hello"-hello-->>> S.sum $ do {yield 1; yield 2}-3-->>> S.sum $ do {yield 1; lift $ putStrLn "/* 1 was yielded */"; yield 2; lift $ putStrLn "/* 2 was yielded */"}-/* 1 was yielded */-/* 2 was yielded */-3--->>> let prompt :: IO Int; prompt = putStrLn "Enter a number:" >> readLn ->>> S.sum $ do {lift prompt >>= yield ; lift prompt >>= yield ; lift prompt >>= yield}-Enter a number:-3<Enter>-Enter a number:-20<Enter>-Enter a number:-100<Enter>-123---}--yield :: Monad m => a -> Stream (Of a) m ()-yield a = Step (a :> Return ())-{-# INLINE yield #-}---- | Zip two 'Streams's -zip :: Monad m- => (Stream (Of a) m r)- -> (Stream (Of b) m r)- -> (Stream (Of (a,b)) m r)-zip = zipWith (,)-{-# INLINE zip #-}---- | Zip two 'Streams's using the provided combining function-zipWith :: Monad m- => (a -> b -> c)- -> (Stream (Of a) m r)- -> (Stream (Of b) m r)- -> (Stream (Of c) m r)-zipWith f = loop- where- loop str0 str1 = case str0 of- Return r -> Return r- Effect m -> Effect $ liftM (\str -> loop str str1) m - Step (a :> rest0) -> case str1 of- Return r -> Return r- Effect m -> Effect $ liftM (loop str0) m- Step (b :> rest1) -> Step (f a b :>loop rest0 rest1)-{-# INLINABLE zipWith #-}----- | Zip three 'Stream's with a combining function-zipWith3 :: Monad m =>- (a -> b -> c -> d)- -> Stream (Of a) m r- -> Stream (Of b) m r- -> Stream (Of c) m r- -> Stream (Of d) m r-zipWith3 op = loop where- loop str0 str1 str2 = do- e0 <- lift (next str0)- case e0 of - Left r0 -> return r0- Right (a0,rest0) -> do - e1 <- lift (next str1)- case e1 of- Left r1 -> return r1- Right (a1,rest1) -> do - e2 <- lift (next str2)- case e2 of- Left r2 -> return r2- Right (a2,rest2) -> do - yield (op a0 a1 a2)- loop rest0 rest1 rest2-{-# INLINABLE zipWith3 #-} - - --- | Zip three streams together -zip3 :: Monad m- => (Stream (Of a) m r)- -> (Stream (Of b) m r)- -> (Stream (Of c) m r)- -> (Stream (Of (a,b,c)) m r)-zip3 = zipWith3 (,,)-{-# INLINABLE zip3 #-}---- ----------------- IO fripperies --- ----------------{-| repeatedly stream lines as 'String' from stdin-->>> stdoutLn $ S.show (S.each [1..3])-1-2-3-->>> stdoutLn stdinLn -hello<Enter>-hello-world<Enter>-world-^CInterrupted.--->>> stdoutLn $ S.map reverse stdinLn -hello<Enter>-olleh-world<Enter>-dlrow-^CInterrupted.---}-stdinLn :: MonadIO m => Stream (Of String) m ()-stdinLn = fromHandle IO.stdin-{-# INLINABLE stdinLn #-}--{-| Read values from 'IO.stdin', ignoring failed parses-->>> S.sum $ S.take 2 S.readLn :: IO Int-3<Enter>-#$%^&\^?<Enter>-1000<Enter>-1003--}--readLn :: (MonadIO m, Read a) => Stream (Of a) m ()-readLn = for stdinLn $ \str -> case readMaybe str of - Nothing -> return ()- Just n -> yield n-{-# INLINABLE readLn #-}--{-| Read 'String's from a 'IO.Handle' using 'IO.hGetLine'-- Terminates on end of input-->>> withFile "distribute.hs" ReadMode $ stdoutLn . S.take 3 . fromHandle-import Streaming-import qualified Streaming.Prelude as S-import Control.Monad.Trans.State.Strict---}-fromHandle :: MonadIO m => IO.Handle -> Stream (Of String) m ()-fromHandle h = go- where- go = do- eof <- liftIO $ IO.hIsEOF h- unless eof $ do- str <- liftIO $ IO.hGetLine h- yield str- go-{-# INLINABLE fromHandle #-} --toHandle :: MonadIO m => IO.Handle -> Stream (Of String) m r -> m r-toHandle handle = loop where- loop str = case str of- Return r -> return r- Effect m -> m >>= loop - Step (s :> rest) -> do - liftIO $ IO.hPutStrLn handle s- loop rest-{-# INLINABLE toHandle #-} --{-| Print the elements of a stream as they arise.--}-print :: (MonadIO m, Show a) => Stream (Of a) m r -> m r-print = loop where- loop stream = case stream of - Return r -> return r - Effect m -> m >>= loop- Step (a :> rest) -> do - liftIO (Prelude.print a)- loop rest---- -- | Evaluate all values flowing downstream to WHNF--- seq :: Monad m => Stream (Of a) m r -> Stream (Of a) m r--- seq str = for str $ \a -> yield $! a--- {-# INLINABLE seq #-}--{-| Write 'String's to 'IO.stdout' using 'putStrLn'; terminates on a broken output pipe- (compare 'Pipes.Prelude.stdoutLn').-->>> S.stdoutLn $ S.show (S.each [1..3])-1-2-3--}-stdoutLn :: MonadIO m => Stream (Of String) m () -> m ()-stdoutLn = loop- where- loop stream = case stream of - Return _ -> return () - Effect m -> m >>= loop- Step (s :> rest) -> do- x <- liftIO $ try (putStrLn s)- case x of- Left (G.IOError { G.ioe_type = G.ResourceVanished- , G.ioe_errno = Just ioe })- | Errno ioe == ePIPE- -> return ()- Left e -> liftIO (throwIO e)- Right () -> loop rest-{-# INLINABLE stdoutLn #-}---{-| Write 'String's to 'IO.stdout' using 'putStrLn'-- This does not handle a broken output pipe, but has a polymorphic return- value, which makes this possible:-->>> rest <- stdoutLn' $ S.show $ S.splitAt 3 (each [1..5])-1-2-3->>> S.sum rest -9---}--stdoutLn' :: MonadIO m => Stream (Of String) m r -> m r-stdoutLn' = loop where - loop stream = case stream of - Return r -> return r - Effect m -> m >>= loop- Step (s :> rest) -> liftIO (putStrLn s) >> loop rest-{-# INLINE stdoutLn' #-}----- -- * Producers--- -- $producers--- stdinLn -- --- , readLn -- --- , fromHandle -- --- , repeatM -- --- , replicateM -------- -- * Consumers--- -- $consumers--- , stdoutLn ----- , stdoutLn' ----- , mapM_ ----- , print -- --- , toHandle ----- , effects -------- -- * Pipes--- -- $pipes--- , map -- --- , mapM ----- , sequence -- --- , mapFoldable -- --- , filter ----- , filterM ----- , take ----- , takeWhile ----- , takeWhile' ----- , drop ----- , dropWhile -- --- , concat ----- , elemIndices--- , findIndices--- , scan ----- , scanM ----- , chain ----- , read ----- , show -- --- , seq -------- -- * Folds--- -- $folds--- , fold ----- , fold' ----- , foldM ----- , foldM' ----- , all--- , any--- , and--- , or--- , elem--- , notElem--- , find--- , findIndex--- , head--- , index--- , last--- , length--- , maximum--- , minimum--- , null--- , sum ----- , product ----- , toList ----- , toListM ----- , toListM' -------- -- * Zips--- , zip ----- , zipWith -------distinguish :: (a -> Bool) -> Of a r -> Sum (Of a) (Of a) r-distinguish predicate (a :> b) = if predicate a then InR (a :> b) else InL (a :> b)-{-#INLINE distinguish #-}---eitherToSum :: Of (Either a b) r -> Sum (Of a) (Of b) r-eitherToSum s = case s of - Left a :> r -> InL (a :> r)- Right b :> r -> InR (b :> r)-{-#INLINE eitherToSum #-}-composeToSum :: Compose (Of Bool) f r -> Sum f f r-composeToSum x = case x of - Compose (True :> f) -> InR f- Compose (False :> f) -> InL f-{-#INLINE composeToSum #-}--sumToCompose :: Sum f f r -> Compose (Of Bool) f r -sumToCompose x = case x of- InR f -> Compose (True :> f) - InL f -> Compose (False :> f)-{-#INLINE sumToCompose #-}--duplicate- :: Monad m =>- Stream (Of a) m r -> Stream (Of a) (Stream (Of a) m) r-duplicate = loop where-loop str = do - e <- lift (lift (next str))- case e of- Left r -> return r- Right (a, rest) -> do- yield a - mwrap $ do- yield a- return (loop rest)-{-#INLINABLE duplicate#-}- +{-| This module is very closely modeled on Pipes.Prelude, Pipes.Group and Pipes.Parse. It+ maybe said to give independent expression to the conception of Producer manipulation + articulated in the latter two modules. Because we dispense with piping and + conduiting, the distinction between all of these modules collapses. + The leading type is chosen to permit an api that is as close as possible to that + of Data.List and the Prelude. Thecan + be used with any + rational \"streaming IO\" system. ++ Import qualified thus:++> import Streaming+> import qualified Streaming.Prelude as S++ For the examples below, one sometimes needs++> import Streaming.Prelude (each, yield, stdoutLn, stdinLn)+> import Data.Function ((&)) ++ Other libraries that come up in passing are++> import qualified Control.Foldl as L -- cabal install foldl+> import qualified Pipes as P+> import qualified Pipes.Prelude as P+> import qualified System.IO as IO++ Here are some correspondences between the types employed here and elsewhere:++> streaming | pipes | conduit | io-streams+> -------------------------------------------------------------------------------------------------------------------+> Stream (Of a) m () | Producer a m () | Source m a | InputStream a+> | ListT m a | ConduitM () o m () | Generator r ()+> -------------------------------------------------------------------------------------------------------------------+> Stream (Of a) m r | Producer a m r | ConduitM () o m r | Generator a r+> -------------------------------------------------------------------------------------------------------------------+> Stream (Of a) m (Stream (Of a) m r) | Producer a m (Producer a m r) | +> --------------------------------------------------------------------------------------------------------------------+> Stream (Stream (Of a) m) r | FreeT (Producer a m) m r |+> --------------------------------------------------------------------------------------------------------------------+> --------------------------------------------------------------------------------------------------------------------+> ByteString m () | Producer ByteString m () | Source m ByteString | InputStream ByteString+> --------------------------------------------------------------------------------------------------------------------+> +-}+{-# LANGUAGE RankNTypes, BangPatterns, DeriveDataTypeable, TypeFamilies,+ DeriveFoldable, DeriveFunctor, DeriveTraversable #-}+ +module Streaming.Prelude (+ -- * Types+ Of (..)++ -- * Introducing streams of elements+ -- $producers+ , yield+ , each+ , unfoldr+ , stdinLn+ , readLn+ , fromHandle+ , readFile+ , iterate+ , repeat+ , replicate+ , cycle+ , repeatM+ , replicateM+ , enumFrom+ , enumFromThen+ , seconds+ + -- * Consuming streams of elements+ -- $consumers+ , stdoutLn+ , stdoutLn'+ , mapM_+ , print+ , toHandle+ , writeFile+ , effects+ , drained+ ++ -- * Stream transformers+ -- $pipes+ , map+ , mapM+ , chain+ , maps+ , sequence+ , nub+ , filter+ , filterM+ , for+ , with+ , delay+ , intersperse+ , take+ , takeWhile+-- , takeWhile'+ , drop+ , dropWhile+ , concat+ -- , elemIndices+ -- , findIndices+ , scan+ , scanM+ , scanned+ , read+ , show+ , cons+ , duplicate+ , store++ -- * Splitting and inspecting streams of elements+ , next+ , uncons+ , splitAt+ , split+-- , breaks+ , break+ , breakWhen+ , span+ , group+ , groupBy+ -- , groupedBy+ -- , split+ ++ -- * Sum and Compose manipulation+ + , distinguish + , switch+ , separate+ , unseparate+ , eitherToSum+ , sumToEither+ , sumToCompose+ , composeToSum+ + -- * Folds+ -- $folds+ , fold+ , fold_+ , foldM+ , foldM_+ , all+ , all_+ , any+ , any_+ , sum+ , sum_+ , product+ , product_+ , head+ , head_+ , last+ , last_+ , elem+ , elem_+ , length+ , length_+ , toList+ , toList_+ , mconcat+ , mconcat_+ , minimum+ , minimum_+ , maximum+ , maximum_+ , foldrM+ , foldrT+ + + -- , all+ -- , any+ -- , and+ -- , or+ -- , elem+ -- , notElem+ -- , find+ -- , findIndex+ -- , head+ -- , index+ -- , last+ -- , length+ -- , maximum+ -- , minimum+ -- , null++ -- * Zips and unzips+ , zip+ , zipWith+ , zip3+ , zipWith3+ , unzip+ + -- * Pair manipulation+ , lazily+ , strictly+ , fst'+ , snd'+ + -- * Interoperation+ , reread+ + -- * Basic Type+ , Stream++ ) where+import Streaming.Internal++import Control.Monad hiding (filterM, mapM, mapM_, foldM, foldM_, replicateM, sequence)+import Data.Data ( Data, Typeable )+import Data.Functor.Identity+import Data.Functor.Sum+import Control.Monad.Trans+import Control.Applicative (Applicative (..))+import Data.Functor (Functor (..), (<$))++import qualified Prelude as Prelude +import Data.Foldable (Foldable)+import Data.Traversable (Traversable)+import qualified Data.Foldable as Foldable+import Text.Read (readMaybe)+import Prelude hiding (map, mapM, mapM_, filter, drop, dropWhile, take, mconcat, sum, product+ , iterate, repeat, cycle, replicate, splitAt+ , takeWhile, enumFrom, enumFromTo, enumFromThen, length+ , print, zipWith, zip, zipWith3, zip3, unzip, seq, show, read+ , readLn, sequence, concat, span, break, readFile, writeFile+ , minimum, maximum, elem, intersperse, all, any, head, last)++import qualified GHC.IO.Exception as G+import qualified System.IO as IO+import Foreign.C.Error (Errno(Errno), ePIPE)+import Control.Exception (throwIO, try)+import Data.Monoid (Monoid (mappend, mempty))+import Data.String (IsString (..))+import Control.Concurrent (threadDelay)+import Data.Time (getCurrentTime, diffUTCTime, picosecondsToDiffTime)+import Data.Functor.Classes+import Data.Functor.Compose+import Control.Monad.Trans.Resource+import qualified Data.Set as Set++import GHC.Exts ( SpecConstrAnnotation(..) )+++data SPEC = SPEC | SPEC2 ++{-# ANN type SPEC ForceSpecConstr #-}+-- | A left-strict pair; the base functor for streams of individual elements.+data Of a b = !a :> b+ deriving (Data, Eq, Foldable, Ord,+ Read, Show, Traversable, Typeable)+infixr 5 :>++instance (Monoid a, Monoid b) => Monoid (Of a b) where+ mempty = mempty :> mempty+ {-#INLINE mempty #-}+ mappend (m :> w) (m' :> w') = mappend m m' :> mappend w w'+ {-#INLINE mappend #-}++instance Functor (Of a) where+ fmap f (a :> x) = a :> f x+ {-#INLINE fmap #-}+ a <$ (b :> x) = b :> a+ {-#INLINE (<$) #-}++instance Monoid a => Applicative (Of a) where+ pure x = mempty :> x+ {-#INLINE pure #-}+ m :> f <*> m' :> x = mappend m m' :> f x+ {-#INLINE (<*>) #-}+ m :> x *> m' :> y = mappend m m' :> y+ {-#INLINE (*>) #-}+ m :> x <* m' :> y = mappend m m' :> x + {-#INLINE (<*) #-}++instance Monoid a => Monad (Of a) where+ return x = mempty :> x+ {-#INLINE return #-}+ m :> x >> m' :> y = mappend m m' :> y+ {-#INLINE (>>) #-}+ m :> x >>= f = let m' :> y = f x in mappend m m' :> y+ {-#INLINE (>>=) #-}++instance (r ~ (), Monad m, f ~ Of Char) => IsString (Stream f m r) where+ fromString = each++instance (Eq a) => Eq1 (Of a) where eq1 = (==)+instance (Ord a) => Ord1 (Of a) where compare1 = compare+instance (Read a) => Read1 (Of a) where readsPrec1 = readsPrec+instance (Show a) => Show1 (Of a) where showsPrec1 = showsPrec++{-| Note that 'lazily', 'strictly', 'fst'', and 'mapOf' are all so-called /natural transformations/ on the primitive @Of a@ functor+ If we write + +> type f ~~> g = forall x . f x -> g x+ + then we can restate some types as follows:+ +> mapOf :: (a -> b) -> Of a ~~> Of b -- bifunctor lmap+> lazily :: Of a ~~> (,) a+> Identity . fst' :: Of a ~~> Identity a++ Manipulation of a @Stream f m r@ by mapping often turns on recognizing natural transformations of @f@,+ thus @maps@ is far more general the the @map@ of the present module, which can be+ defined thus:++> S.map :: (a -> b) -> Stream (Of a) m r -> Stream (Of b) m r+> S.map f = maps (mapOf f)+ + This rests on recognizing that @mapOf@ is a natural transformation; note though+ that it results in such a transformation as well:+ +> S.map :: (a -> b) -> Stream (Of a) m ~> Stream (Of b) m ++-}+lazily :: Of a b -> (a,b)+lazily = \(a:>b) -> (a,b)+{-# INLINE lazily #-}++strictly :: (a,b) -> Of a b+strictly = \(a,b) -> a :> b+{-# INLINE strictly #-}++fst' :: Of a b -> a+fst' (a :> b) = a++snd' :: Of a b -> b+snd' (a :> b) = b++mapOf :: (a -> b) -> Of a r -> Of b r+mapOf f (a:> b) = (f a :> b)+++all :: Monad m => (a -> Bool) -> Stream (Of a) m r -> m (Of Bool r)+all thus = loop True where+ loop b str = case str of+ Return r -> return (b :> r)+ Effect m -> m >>= loop b+ Step (a :> rest) -> if thus a+ then loop True rest+ else do + r <- effects rest+ return (False :> r)+{-#INLINABLE all #-}++all_ :: Monad m => (a -> Bool) -> Stream (Of a) m r -> m Bool+all_ thus = loop True where+ loop b str = case str of+ Return r -> return b+ Effect m -> m >>= loop b+ Step (a :> rest) -> if thus a+ then loop True rest+ else return False+{-#INLINABLE all_ #-}+++any :: Monad m => (a -> Bool) -> Stream (Of a) m r -> m (Of Bool r)+any thus = loop False where+ loop b str = case str of+ Return r -> return (b :> r)+ Effect m -> m >>= loop b+ Step (a :> rest) -> if thus a+ then do + r <- effects rest+ return (True :> r)+ else loop False rest+{-#INLINABLE any #-}++any_ :: Monad m => (a -> Bool) -> Stream (Of a) m r -> m Bool+any_ thus = loop False where+ loop b str = case str of+ Return r -> return b+ Effect m -> m >>= loop b+ Step (a :> rest) -> if thus a+ then return True+ else loop False rest +{-#INLINABLE any_ #-}+ +{-| Break a sequence upon meeting element falls under a predicate, + keeping it and the rest of the stream as the return value.++>>> rest <- S.print $ S.break even $ each [1,1,2,3] +1+1+>>> S.print rest+2+3++-}++break :: Monad m => (a -> Bool) -> Stream (Of a) m r + -> Stream (Of a) m (Stream (Of a) m r)+break pred = loop where+ loop str = case str of + Return r -> Return (Return r)+ Effect m -> Effect $ liftM loop m+ Step (a :> rest) -> if (pred a) + then Return (Step (a :> rest))+ else Step (a :> loop rest)+{-# INLINABLE break #-}++{-| Yield elements, using a fold to maintain state, until the accumulated + value satifies the supplied predicate. The fold will then be short-circuited + and the element that breaks it will be put after the break.+ This function is easiest to use with 'Control.Foldl.purely'++>>> rest <- each [1..10] & L.purely S.breakWhen L.sum (>10) & S.print +1+2+3+4+>>> S.print rest+5+6+7+8+9+10++-}+breakWhen :: Monad m => (x -> a -> x) -> x -> (x -> b) -> (b -> Bool) -> Stream (Of a) m r -> Stream (Of a) m (Stream (Of a) m r)+breakWhen step begin done pred = loop0 begin+ where+ loop0 x stream = case stream of + Return r -> return (return r)+ Effect mn -> Effect $ liftM (loop0 x) mn+ Step (a :> rest) -> loop a (step x a) rest+ loop a !x stream = do+ if pred (done x) + then return (yield a >> stream) + else case stream of + Return r -> yield a >> return (return r)+ Effect mn -> Effect $ liftM (loop a x) mn+ Step (a' :> rest) -> do+ yield a+ loop a' (step x a') rest+{-# INLINABLE breakWhen #-}++-- -- Break during periods where the predicate is not satisfied, grouping the periods when it is.+--+-- >>> S.print $ mapped S.toList $ S.breaks not $ S.each [False,True,True,False,True,True,False]+-- [True,True]+-- [True,True]+-- >>> S.print $ mapped S.toList $ S.breaks id $ S.each [False,True,True,False,True,True,False]+-- [False]+-- [False]+-- [False]+--+-- -}+-- breaks+-- :: Monad m =>+-- (a -> Bool) -> Stream (Of a) m r -> Stream (Stream (Of a) m) m r+-- breaks thus = loop where+-- loop stream = Effect $ do+-- e <- next stream+-- return $ case e of+-- Left r -> Return r+-- Right (a, p') ->+-- if not (thus a)+-- then Step $ fmap loop (yield a >> break thus p')+-- else loop p'+-- {-#INLINABLE breaks #-}++{-| Apply an action to all values, re-yielding each++>>> S.product $ S.chain Prelude.print $ S.each [1..5]+1+2+3+4+5+120 :> ()+-}++chain :: Monad m => (a -> m ()) -> Stream (Of a) m r -> Stream (Of a) m r+chain f = loop where + loop str = case str of + Return r -> return r+ Effect mn -> Effect (liftM loop mn)+ Step (a :> rest) -> Effect $ do+ f a+ return (Step (a :> loop rest))+{-# INLINABLE chain #-}++{-| Make a stream of traversable containers into a stream of their separate elements.+ This is just ++> concat = for str each++>>> S.print $ S.concat (each ["xy","z"])+'x'+'y'+'z'++ Note that it also has the effect of 'Data.Maybe.catMaybes', 'Data.Either.rights'+ 'map snd' and such-like operations.++>>> S.print $ S.concat $ S.each [Just 1, Nothing, Just 2]+1+2+>>> S.print $ S.concat $ S.each [Right 1, Left "Error!", Right 2]+1+2+>>> S.print $ S.concat $ S.each [('A',1), ('B',2)]+1+2++-}++concat :: (Monad m, Foldable.Foldable f) => Stream (Of (f a)) m r -> Stream (Of a) m r+concat str = for str each+{-# INLINE concat #-}++{-| The natural @cons@ for a @Stream (Of a)@. ++> cons a stream = yield a >> stream++ Useful for interoperation:++> Data.Text.foldr S.cons (return ()) :: Text -> Stream (Of Char) m ()+> Lazy.foldrChunks S.cons (return ()) :: Lazy.ByteString -> Stream (Of Strict.ByteString) m ()++ and so on.+-}++cons :: (Monad m) => a -> Stream (Of a) m r -> Stream (Of a) m r+cons a str = Step (a :> str)+{-# INLINE cons #-}++{- | Cycle repeatedly through the layers of a stream, /ad inf./ This+ function is functor-general++> cycle = forever++>>> rest <- S.print $ S.splitAt 3 $ S.cycle (yield 0 >> yield 1)+True+False+True+>>> S.print $ S.take 3 rest+False+True+False++-}++cycle :: (Monad m, Functor f) => Stream f m r -> Stream f m s+cycle str = loop where loop = str >> loop+{-#INLINABLE cycle #-}+++{-| A+++-}+delay :: MonadIO m => Double -> Stream (Of a) m r -> Stream (Of a) m r+delay seconds = loop where+ pico = truncate (seconds * 1000000)+ loop str = do + e <- lift $ next str+ case e of+ Left r -> Return r+ Right (a,rest) -> do+ yield a+ liftIO $ threadDelay pico+ loop rest+{-#INLINABLE delay #-}++-- ---------------+-- effects+-- ---------------++{- | Reduce a stream, performing its actions but ignoring its elements. + +>>> rest <- S.effects $ S.splitAt 2 $ each [1..5]+>>> S.print rest+3+4+5+++-}+effects :: Monad m => Stream (Of a) m r -> m r+effects = loop where+ loop stream = case stream of + Return r -> return r+ Effect m -> m >>= loop + Step (_ :> rest) -> loop rest+{-#INLINABLE effects #-}+ +{-| Where a transformer returns a stream, run the effects of the stream, keeping+ the return value. This is usually used at the type++> drained :: Monad m => Stream (Of a) m (Stream (Of b) m r) -> Stream (Of a) m r+> drained = join . fmap (lift . effects)+ + Here, for example, we split a stream in two places and throw out the middle segment:+ +>>> rest <- S.print $ S.drained $ S.splitAt 2 $ S.splitAt 5 $ each [1..7]+1+2+>>> S.print rest+6+7++ In particular, we can define versions of @take@ and @takeWhile@ which + retrieve the return value of the rest of the stream - and which can + thus be used with 'maps':++> take' n = S.drained . S.splitAt n+> takeWhile' thus = S.drained . S.span thus++-}+drained :: (Monad m, Monad (t m), Functor (t m), MonadTrans t) => t m (Stream (Of a) m r) -> t m r+drained = join . fmap (lift . effects)+{-#INLINE drained #-}++-- ---------------+-- drop+-- ---------------+{-| Ignore the first n elements of a stream, but carry out the actions++>>> S.toList $ S.drop 2 $ S.replicateM 5 getLine +a<Enter>+b<Enter>+c<Enter>+d<Enter>+e<Enter>+["c","d","e"] :> ()++ Because it retains the final return value, @drop n@ is a suitable argument + for @maps@:++>>> S.toList $ concats $ maps (S.drop 4) $ chunksOf 5 $ each [1..20]+[5,10,15,20] :> ()++ ++ -}++drop :: (Monad m) => Int -> Stream (Of a) m r -> Stream (Of a) m r+drop = loop where+ loop 0 stream = stream+ loop n stream = case stream of+ Return r -> Return r+ Effect ma -> Effect (liftM (loop n) ma)+ Step (a :> as) -> loop (n-1) as+{-# INLINABLE drop #-}++-- ---------------+-- dropWhile+-- ---------------++{- | Ignore elements of a stream until a test succeeds, retaining the rest.++>>> S.print $ S.dropWhile ((< 5) . length) S.stdinLn +one<Enter>+two<Enter>+three<Enter>+"three"+four<Enter>+"four"+^CInterrupted.+++-}+dropWhile :: Monad m => (a -> Bool) -> Stream (Of a) m r -> Stream (Of a) m r+dropWhile pred = loop where + loop stream = case stream of+ Return r -> Return r+ Effect ma -> Effect (liftM loop ma)+ Step (a :> as) -> if pred a + then loop as+ else Step (a :> as)+{-# INLINABLE dropWhile #-}++-- ---------------+-- each +-- ---------------++{- | Stream the elements of a pure, foldable container.++>>> each [1..3] & S.print+1+2+3+>>> S.replicateM 5 getLine & chunksOf 3 & mapped S.toList & S.print+s+t+u+["s","t","u"]+v+w+["v","w"]++-}+each :: (Monad m, Foldable.Foldable f) => f a -> Stream (Of a) m ()+each = Foldable.foldr (\a p -> (Step (a :> p))) (Return ())+{-# INLINABLE each #-}++{-| Exhaust a stream remembering only whether @a@ was an element.++-}++elem :: (Monad m, Eq a) => a -> Stream (Of a) m r -> m (Of Bool r)+elem a = fold op False id where+ op True _ = True+ op False a' | a == a' = True+ op _ _ = False+{-#INLINABLE elem #-}+ +elem_ :: (Monad m, Eq a) => a -> Stream (Of a) m r -> m Bool+elem_ a = fold_ op False id where+ op True _ = True+ op False a' | a == a' = True+ op _ _ = False+{-#INLINABLE elem_ #-}++-- -----+-- enumFrom+-- ------++{-| An infinite stream of enumerable values, starting from a given value.+ It is the same as `S.iterate succ`. + Because their return type is polymorphic, @enumFrom@ and @enumFromThen@+ (and @iterate@ are useful for example with @zip@+ and @zipWith@, which require the same return type in the zipped streams. + With @each [1..]@ the following bit of connect-and-resume would be impossible:++>>> rest <- S.print $ S.zip (S.enumFrom 'a') $ S.splitAt 3 $ S.enumFrom 1+('a',1)+('b',2)+('c',3)+>>> S.print $ S.take 3 rest+4+5+6++-}+enumFrom :: (Monad m, Enum n) => n -> Stream (Of n) m r+enumFrom = loop where+ loop !n = Step (n :> loop (succ n))+{-# INLINABLE enumFrom #-}+++{-| An infinite sequence of enumerable values at a fixed distance, determined+ by the first and second values. See the discussion of 'Streaming.enumFrom'++>>> S.print $ S.take 3 $ S.enumFromThen 100 200+100+200+300++-}+enumFromThen:: (Monad m, Enum a) => a -> a -> Stream (Of a) m r+enumFromThen first second = Streaming.Prelude.map toEnum (loop _first)+ where+ _first = fromEnum first+ _second = fromEnum second+ diff = _second - _first+ loop !s = Step (s :> loop (s+diff))+{-# INLINABLE enumFromThen #-}++-- ---------------+-- filter +-- ---------------++-- | Skip elements of a stream that fail a predicate+filter :: (Monad m) => (a -> Bool) -> Stream (Of a) m r -> Stream (Of a) m r+filter pred = loop where+ loop str = case str of+ Return r -> Return r+ Effect m -> Effect (liftM loop m)+ Step (a :> as) -> if pred a + then Step (a :> loop as)+ else loop as+{-# INLINABLE filter #-}++-- ---------------+-- filterM+-- ---------------++-- | Skip elements of a stream that fail a monadic test+filterM :: (Monad m) => (a -> m Bool) -> Stream (Of a) m r -> Stream (Of a) m r+filterM pred = loop where+ loop str = case str of+ Return r -> Return r+ Effect m -> Effect $ liftM loop m+ Step (a :> as) -> Effect $ do + bool <- pred a+ if bool + then return $ Step (a :> loop as)+ else return $ loop as+{-# INLINABLE filterM #-}++-- ---------------+-- fold+-- ---------------++{- $folds+ Use these to fold the elements of a 'Stream'. ++>>> S.fold_ (+) 0 id $ S.each [1..0]+50++ The general folds 'fold', fold_', 'foldM' and 'foldM_' are arranged + for use with 'Control.Foldl'++>>> L.purely fold_ L.sum $ each [1..10]+55+>>> L.purely fold_ (liftA3 (,,) L.sum L.product L.list) $ each [1..10]+(55,3628800,[1,2,3,4,5,6,7,8,9,10])++ All functions marked with an underscore omit + (e.g. @fold_@, @sum_@) the stream's return value in a left-strict pair.+ They are good for exiting streaming completely, + but when you are, e.g. @mapped@-ing over a @Stream (Stream (Of a) m) m r@, + which is to be compared with @[[a]]@. Specializing, we have e.g.++> mapped sum :: (Monad m, Num n) => Stream (Stream (Of Int)) IO () -> Stream (Of n) IO ()+> mapped (fold mappend mempty id) :: Stream (Stream (Of Int)) IO () -> Stream (Of Int) IO ()++>>> S.print $ mapped S.sum $ chunksOf 3 $ S.each [1..10]+6+15+24+10++>>> let three_folds = L.purely S.fold (liftA3 (,,) L.sum L.product L.list)+>>> S.print $ mapped three_folds $ chunksOf 3 (each [1..10])+(6,6,[1,2,3])+(15,120,[4,5,6])+(24,504,[7,8,9])+(10,10,[10])+-}++{-| Strict fold of a 'Stream' of elements, preserving only the result of the fold, not+ the return value of the stream. The third parameter will often be 'id' where a fold+ is written by hand:++>>> S.fold_ (+) 0 id $ each [1..10]+55 + + It can be used to replace a standard Haskell type with one more suited to + writing a strict accumulation function. It is also crucial to the + Applicative instance for @Control.Foldl.Fold@++> Control.Foldl.purely fold :: Monad m => Fold a b -> Stream (Of a) m () -> m b+-}+fold_ :: Monad m => (x -> a -> x) -> x -> (x -> b) -> Stream (Of a) m r -> m b+fold_ step begin done = liftM (\(a:>rest) -> a) . fold step begin done+{-#INLINE fold_ #-}++{-| Strict fold of a 'Stream' of elements that preserves the return value. + The third parameter will often be 'id' where a fold is written by hand:++>>> S.fold (+) 0 id $ each [1..10]+55 :> ()++>>> S.fold (*) 1 id $ S.fold (+) 0 id $ S.duplicate $ each [1..10]+3628800 :> (55 :> ())+++ It can be used to replace a standard Haskell type with one more suited to + writing a strict accumulation function. It is also crucial to the + Applicative instance for @Control.Foldl.Fold@ We can apply such a fold+ @purely@++> Control.Foldl.purely S.fold :: Monad m => Fold a b -> Stream (Of a) m r -> m (Of b r)++ Thus, specializing a bit:++> L.purely S.fold L.sum :: Stream (Of Int) Int r -> m (Of Int r)+> maps (L.purely S.fold L.sum) :: Stream (Stream (Of Int)) IO r -> Stream (Of Int) IO r++ Here we use the Applicative instance for @Control.Foldl.Fold@ to + stream three-item segments of a stream together with their sums and products.++>>> S.print $ mapped (L.purely S.fold (liftA3 (,,) L.list L.product L.sum)) $ chunksOf 3 $ each [1..10]+([1,2,3],6,6)+([4,5,6],120,15)+([7,8,9],504,24)+([10],10,10)++-}++fold :: Monad m => (x -> a -> x) -> x -> (x -> b) -> Stream (Of a) m r -> m (Of b r)+fold step begin done str = fold_loop str begin+ where+ fold_loop stream !x = case stream of + Return r -> return (done x :> r)+ Effect m -> m >>= \str' -> fold_loop str' x+ Step (a :> rest) -> fold_loop rest $! step x a+{-# INLINABLE fold #-}+++{-| Strict, monadic fold of the elements of a 'Stream (Of a)'++> Control.Foldl.impurely foldM :: Monad m => FoldM a b -> Stream (Of a) m () -> m b+-}+foldM_+ :: Monad m+ => (x -> a -> m x) -> m x -> (x -> m b) -> Stream (Of a) m r -> m b+foldM_ step begin done = liftM (\(a:>rest) -> a) . foldM step begin done+{-#INLINE foldM_ #-}++{-| Strict, monadic fold of the elements of a 'Stream (Of a)'++> Control.Foldl.impurely foldM' :: Monad m => FoldM a b -> Stream (Of a) m r -> m (b, r)++ Thus to accumulate the elements of a stream as a vector, together with a random+ element we might write:++>>> L.impurely S.foldM (liftA2 (,) L.vector L.random) $ each [1..10::Int] :: IO (Of (U.Vector Int,Maybe Int) ())+([1,2,3,4,5,6,7,8,9,10],Just 9) :> ()++-}+foldM+ :: Monad m+ => (x -> a -> m x) -> m x -> (x -> m b) -> Stream (Of a) m r ->m (Of b r)+foldM step begin done str = do+ x0 <- begin+ loop str x0+ where+ loop stream !x = case stream of + Return r -> done x >>= \b -> return (b :> r)+ Effect m -> m >>= \s -> loop s x+ Step (a :> rest) -> do+ x' <- step x a+ loop rest x'+{-# INLINABLE foldM #-}++++{-| A natural right fold for consuming a stream of elements. + See also the more general 'iterTM' in the 'Streaming' module + and the still more general 'destroy'++> foldrT (\a p -> Pipes.yield a >> p) :: Monad m => Stream (Of a) m r -> Producer a m r+> foldrT (\a p -> Conduit.yield a >> p) :: Monad m => Stream (Of a) m r -> Conduit a m r++-}++foldrT :: (Monad m, MonadTrans t, Monad (t m)) + => (a -> t m r -> t m r) -> Stream (Of a) m r -> t m r+foldrT step = loop where+ loop stream = case stream of+ Return r -> return r+ Effect m -> lift m >>= loop+ Step (a :> as) -> step a (loop as)+{-# INLINABLE foldrT #-} ++{-| A natural right fold for consuming a stream of elements.+ See also the more general 'iterT' in the 'Streaming' module and the+ still more general 'destroy'+-}+foldrM :: Monad m + => (a -> m r -> m r) -> Stream (Of a) m r -> m r+foldrM step = loop where+ loop stream = case stream of+ Return r -> return r+ Effect m -> m >>= loop+ Step (a :> as) -> step a (loop as)+{-# INLINABLE foldrM #-} ++-- ---------------+-- for+-- ---------------++-- | @for@ replaces each element of a stream with an associated stream. Note that the+-- associated stream may layer any functor. +for :: (Monad m, Functor f) => Stream (Of a) m r -> (a -> Stream f m x) -> Stream f m r+for str0 act = loop str0 where+ loop str = case str of+ Return r -> Return r + Effect m -> Effect $ liftM loop m+ Step (a :> rest) -> do+ act a+ loop rest+{-# INLINABLE for #-}++-- -| Group layers of any functor by comparisons on a preliminary annotation ++-- groupedBy+-- :: (Monad m, Functor f) =>+-- (a -> a -> Bool)+-- -> Stream (Compose (Of a) f) m r+-- -> Stream (Stream (Compose (Of a) f) m) m r+-- groupedBy equals = loop where+-- loop stream = Effect $ do+-- e <- inspect stream+-- return $ case e of+-- Left r -> Return r+-- Right s@(Compose (a :> p')) -> Step $+-- fmap loop (Step $ Compose (a :> fmap (span' (equals a)) p'))+-- span' :: (Monad m, Functor f) => (a -> Bool) -> Stream (Compose (Of a) f) m r+-- -> Stream (Compose (Of a) f) m (Stream (Compose (Of a) f) m r)+-- span' pred = loop where+-- loop str = case str of+-- Return r -> Return (Return r)+-- Effect m -> Effect $ liftM loop m+-- Step s@(Compose (a :> rest)) -> case pred a of+-- True -> Step (Compose (a :> fmap loop rest))+-- False -> Return (Step s)+-- {-# INLINABLE groupedBy #-}++{-| Group elements of a stream in accordance with the supplied comparison. +++>>> S.print $ mapped S.toList $ S.groupBy (>=) $ each [1,2,3,1,2,3,4,3,2,4,5,6,7,6,5]+[1]+[2]+[3,1,2,3]+[4,3,2,4]+[5]+[6]+[7,6,5]++-}+groupBy :: Monad m + => (a -> a -> Bool)+ -> Stream (Of a) m r + -> Stream (Stream (Of a) m) m r+groupBy equals = loop where+ loop stream = Effect $ do+ e <- next stream+ return $ case e of+ Left r -> Return r+ Right (a, p') -> Step $+ fmap loop (yield a >> span (equals a) p')+{-# INLINABLE groupBy #-} +++{-| Group successive equal items together++>>> S.toList $ mapped S.toList $ S.group $ each "baaaaad"+["b","aaaaa","d"] :> ()++>>> S.toList $ concats $ maps (S.drained . S.splitAt 1) $ S.group $ each "baaaaaaad"+"bad" :> ()++-}+group :: (Monad m, Eq a) => Stream (Of a) m r -> Stream (Stream (Of a) m) m r +group = groupBy (==)+{-#INLINE group #-}+++head :: Monad m => Stream (Of a) m r -> m (Of (Maybe a) r)+head str = case str of+ Return r -> return (Nothing :> r)+ Effect m -> m >>= head+ Step (a :> rest) -> effects rest >>= \r -> return (Just a :> r)+{-#INLINABLE head #-}+ +head_ :: Monad m => Stream (Of a) m r -> m (Maybe a) +head_ str = case str of+ Return r -> return Nothing+ Effect m -> m >>= head_+ Step (a :> rest) -> effects rest >> return (Just a)+{-#INLINABLE head_ #-}+ +intersperse :: Monad m => a -> Stream (Of a) m r -> Stream (Of a) m r+intersperse x str = case str of+ Return r -> Return r+ Effect m -> Effect (liftM (intersperse x) m)+ Step (a :> rest) -> loop a rest+ where+ loop !a str = case str of+ Return r -> Step (a :> Return r)+ Effect m -> Effect (liftM (loop a) m)+ Step (b :> rest) -> Step (a :> Step (x :> loop b rest))+{-#INLINABLE intersperse #-}+ + + ++-- ---------------+-- iterate+-- ---------------++{-| Iterate a pure function from a seed value, streaming the results forever+ +++-}+iterate :: (a -> a) -> a -> Stream (Of a) m r+iterate f = loop where+ loop a' = Step (a' :> loop (f a'))+{-# INLINABLE iterate #-}++-- | Iterate a monadic function from a seed value, streaming the results forever+iterateM :: Monad m => (a -> m a) -> m a -> Stream (Of a) m r+iterateM f = loop where+ loop ma = Effect $ do + a <- ma+ return (Step (a :> loop (f a)))+{-# INLINABLE iterateM #-}++++last :: Monad m => Stream (Of a) m r -> m (Of (Maybe a) r)+last = loop Nothing_ where+ loop m str = case str of+ Return r -> case m of + Nothing_ -> return (Nothing :> r)+ Just_ a -> return (Just a :> r)+ Effect m -> m >>= last+ Step (a :> rest) -> loop (Just_ a) rest+{-#INLINABLE last #-}+ +++last_ :: Monad m => Stream (Of a) m r -> m (Maybe a) +last_ = loop Nothing_ where+ loop m str = case str of+ Return r -> case m of + Nothing_ -> return Nothing + Just_ a -> return (Just a)+ Effect m -> m >>= last_+ Step (a :> rest) -> loop (Just_ a) rest+{-#INLINABLE last_ #-}+ +-- ---------------+-- length+-- ---------------++{-| Run a stream, remembering only its length:++>>> S.length $ S.each [1..10]+10++-}+length_ :: Monad m => Stream (Of a) m r -> m Int+length_ = fold_ (\n _ -> n + 1) 0 id+{-#INLINE length_#-}++{-| Run a stream, keeping its length and its return value. ++>>> S.print $ mapped S.length $ chunksOf 3 $ S.each [1..10]+3+3+3+1++-}++length :: Monad m => Stream (Of a) m r -> m (Of Int r)+length = fold (\n _ -> n + 1) 0 id+{-#INLINE length #-}+-- ---------------+-- map+-- ---------------++{-| Standard map on the elements of a stream.++>>> S.stdoutLn $ S.map reverse $ each (words "alpha beta")+ahpla+ateb+-}+map :: Monad m => (a -> b) -> Stream (Of a) m r -> Stream (Of b) m r+map f = maps (\(x :> rest) -> f x :> rest)+ -- loop where+ -- loop stream = case stream of+ -- Return r -> Return r+ -- Effect m -> Effect (liftM loop m)+ -- Step (a :> as) -> Step (f a :> loop as)+{-# INLINABLE map #-}+++{-| Replace each element of a stream with the result of a monadic action++>>> S.print $ S.mapM readIORef $ S.chain (\ior -> modifyIORef ior (*100)) $ S.mapM newIORef $ each [1..6]+100+200+300+400+500+600+-}+mapM :: Monad m => (a -> m b) -> Stream (Of a) m r -> Stream (Of b) m r+mapM f = loop where+ loop str = case str of + Return r -> Return r + Effect m -> Effect (liftM loop m)+ Step (a :> as) -> Effect $ do + a' <- f a + return (Step (a' :> loop as) )+{-# INLINABLE mapM #-}++++{-| Reduce a stream to its return value with a monadic action.++>>> S.mapM_ Prelude.print $ each [1..5]+1+2+3+4+5+>>> rest <- S.mapM_ Prelude.print $ S.splitAt 3 $ each [1..10]+1+2+3+>>> S.sum rest+49 :> ()++-}+mapM_ :: Monad m => (a -> m b) -> Stream (Of a) m r -> m r+mapM_ f = loop where+ loop str = case str of + Return r -> return r + Effect m -> m >>= loop+ Step (a :> as) -> do + f a + loop as +{-# INLINABLE mapM_ #-}++{-| Fold streamed items into their monoidal sum++>>> S.mconcat $ S.take 2 $ S.map (Data.Monoid.Last . Just) (S.stdinLn)+first<Enter>+last<Enter>+Last {getLast = Just "last"} :> ()++ -}+mconcat :: (Monad m, Monoid w) => Stream (Of w) m r -> m (Of w r)+mconcat = fold mappend mempty id+{-#INLINE mconcat #-}++data Maybe_ a = Just_ !a | Nothing_+mconcat_ :: (Monad m, Monoid w) => Stream (Of w) m r -> m w+mconcat_ = fold_ mappend mempty id++minimum :: (Monad m, Ord a) => Stream (Of a) m r -> m (Of (Maybe a) r)+minimum = fold (\m a -> case m of Nothing_ -> Just_ a ; Just_ a' -> Just_ (min a a')) + Nothing_+ (\m -> case m of Nothing_ -> Nothing; Just_ r -> Just r)+{-#INLINE minimum #-}++minimum_ :: (Monad m, Ord a) => Stream (Of a) m r -> m (Maybe a) +minimum_ = fold_ (\m a -> case m of Nothing_ -> Just_ a ; Just_ a' -> Just_ (min a a')) + Nothing_+ (\m -> case m of Nothing_ -> Nothing; Just_ r -> Just r)+{-#INLINE minimum_ #-}++maximum :: (Monad m, Ord a) => Stream (Of a) m r -> m (Of (Maybe a) r)+maximum = fold (\m a -> case m of Nothing_ -> Just_ a ; Just_ a' -> Just_ (max a a')) + Nothing_+ (\m -> case m of Nothing_ -> Nothing; Just_ r -> Just r)+{-#INLINE maximum #-}++maximum_ :: (Monad m, Ord a) => Stream (Of a) m r -> m (Maybe a)+maximum_ = fold_ (\m a -> case m of Nothing_ -> Just_ a ; Just_ a' -> Just_ (max a a')) + Nothing_+ (\m -> case m of Nothing_ -> Nothing; Just_ r -> Just r)+{-#INLINE maximum_ #-}++{-| The standard way of inspecting the first item in a stream of elements, if the+ stream is still \'running\'. The @Right@ case contains a + Haskell pair, where the more general @inspect@ would return a left-strict pair. + There is no reason to prefer @inspect@ since, if the @Right@ case is exposed, + the first element in the pair will have been evaluated to whnf.++> next :: Monad m => Stream (Of a) m r -> m (Either r (a, Stream (Of a) m r))+> inspect :: Monad m => Stream (Of a) m r -> m (Either r (Of a (Stream (Of a) m r)))++ Interoperate with @pipes@ producers thus:++> Pipes.unfoldr Stream.next :: Stream (Of a) m r -> Producer a m r+> Stream.unfoldr Pipes.next :: Producer a m r -> Stream (Of a) m r + + Similarly: ++> IOStreams.unfoldM (liftM (either (const Nothing) Just) . next) :: Stream (Of a) IO b -> IO (InputStream a)+> Conduit.unfoldM (liftM (either (const Nothing) Just) . next) :: Stream (Of a) m r -> Source a m r++ But see 'uncons', which is better fitted to these @unfoldM@s+-}+next :: Monad m => Stream (Of a) m r -> m (Either r (a, Stream (Of a) m r))+next = loop where+ loop stream = case stream of+ Return r -> return (Left r)+ Effect m -> m >>= loop+ Step (a :> rest) -> return (Right (a,rest))+{-# INLINABLE next #-}++{-| Remove repeated elements from a Stream. 'nub' of course accumulates a 'Data.Set.Set' of+ elements that have already been seen and should thus be used with care.+ +>>> S.toList_ $ S.nub $ S.take 5 S.readLn :: IO ([Int])+1<Enter>+2<Enter>+3<Enter>+1<Enter>+2<Enter>+[1,2,3]++-}+nub :: (Monad m, Ord a) => Stream (Of a) m r -> Stream (Of a) m r+nub = loop Set.empty where+ loop !set stream = case stream of + Return r -> Return r+ Effect m -> Effect (liftM (loop set) m)+ Step (a :> rest) -> if Set.member a set + then loop set rest+ else Step (a :> loop (Set.insert a set) rest)++-- | Fold a 'Stream' of numbers into their product+product_ :: (Monad m, Num a) => Stream (Of a) m () -> m a+product_ = fold_ (*) 1 id+{-# INLINE product_ #-}++{-| Fold a 'Stream' of numbers into their product with the return value++> maps' product' :: Stream (Stream (Of Int)) m r -> Stream (Of Int) m r+-}+product :: (Monad m, Num a) => Stream (Of a) m r -> m (Of a r)+product = fold (*) 1 id+{-# INLINE product #-}+++-- ---------------+-- read+-- ---------------++{- | Make a stream of strings into a stream of parsed values, skipping bad cases++>>> S.sum_ $ S.read $ S.takeWhile (/= "total") S.stdinLn :: IO Int+1000<Enter>+2000<Enter>+total<Enter>+3000+++-}+read :: (Monad m, Read a) => Stream (Of String) m r -> Stream (Of a) m r+read stream = for stream $ \str -> case readMaybe str of + Nothing -> return ()+ Just r -> yield r+{-# INLINE read #-}++-- ---------------+-- repeat+-- ---------------+{-| Repeat an element /ad inf./ .++>>> S.print $ S.take 3 $ S.repeat 1+1+1+1+-}++repeat :: a -> Stream (Of a) m r+repeat a = loop where loop = Step (a :> loop)+{-# INLINE repeat #-}+++{-| Repeat a monadic action /ad inf./, streaming its results.++>>> S.toList $ S.take 2 $ repeatM getLine+one<Enter>+two<Enter>+["one","two"]+-}++repeatM :: Monad m => m a -> Stream (Of a) m r+repeatM ma = loop where+ loop = do + a <- lift ma + yield a + loop+{-# INLINABLE repeatM #-}++-- ---------------+-- replicate +-- ---------------++-- | Repeat an element several times+replicate :: Monad m => Int -> a -> Stream (Of a) m ()+replicate n a = loop n where+ loop 0 = Return ()+ loop m = Step (a :> loop (m-1))+{-# INLINABLE replicate #-}++{-| Repeat an action several times, streaming the results.++>>> S.print $ S.replicateM 2 getCurrentTime+2015-08-18 00:57:36.124508 UTC+2015-08-18 00:57:36.124785 UTC++-}+replicateM :: Monad m => Int -> m a -> Stream (Of a) m ()+replicateM n ma = loop n where + loop 0 = Return ()+ loop n = Effect $ do + a <- ma + return (Step $ a :> loop (n-1))+{-# INLINABLE replicateM #-}++{-| Read an @IORef (Maybe a)@ or a similar device until it reads @Nothing@.+ @reread@ provides convenient exit from the @io-streams@ library++> reread readIORef :: IORef (Maybe a) -> Stream (Of a) IO ()+> reread Streams.read :: System.IO.Streams.InputStream a -> Stream (Of a) IO ()+-}+reread :: Monad m => (s -> m (Maybe a)) -> s -> Stream (Of a) m ()+reread step s = loop where + loop = Effect $ do + m <- step s+ case m of + Nothing -> return (Return ())+ Just a -> return (Step (a :> loop))+{-# INLINABLE reread #-}++{-| Strict left scan, streaming, e.g. successive partial results.+++>>> S.print $ S.scan (++) "" id $ each (words "a b c d")+""+"a"+"ab"+"abc"+"abcd"++ 'scan' is fitted for use with @Control.Foldl@, thus:++>>> S.print $ L.purely S.scan L.list $ each [3..5]+[]+[3]+[3,4]+[3,4,5]++-}+scan :: Monad m => (x -> a -> x) -> x -> (x -> b) -> Stream (Of a) m r -> Stream (Of b) m r+scan step begin done = loop begin+ where+ loop !x stream = Step $ done x :> + case stream of + Return r -> Return r+ Effect m -> Effect $ liftM (loop x) m+ Step (a :> rest) -> loop (step x a) rest+{-# INLINABLE scan #-}++{-| Strict left scan, accepting a monadic function. It can be used with+ 'FoldM's from @Control.Foldl@ using 'impurely'. Here we yield+ a succession of vectors each recording ++>>> let v = L.impurely scanM L.vector $ each [1..4::Int] :: Stream (Of (U.Vector Int)) IO ()+>>> S.print v+fromList []+fromList [1]+fromList [1,2]+fromList [1,2,3]+fromList [1,2,3,4]++-}+scanM :: Monad m => (x -> a -> m x) -> m x -> (x -> m b) -> Stream (Of a) m r -> Stream (Of b) m r+scanM step begin done str = do+ x <- lift begin+ loop x str+ where+ loop !x stream = do + b <- lift (done x)+ yield b+ case stream of + Return r -> Return r+ Effect m -> Effect (do + stream' <- m+ return (loop x stream')+ )+ Step (a :> rest) -> Effect (do+ x' <- step x a+ return (loop x' rest)+ )+{-# INLINABLE scanM #-}++{- Label each element in a stream with a value accumulated according to a fold.+++>>> S.print $ S.scanned (*) 1 id $ S.each [100,200,300]+(100,100)+(200,20000)+(300,6000000)++>>> S.print $ L.purely S.scanned L.product $ S.each [100,200,300]+(100,100)+(200,20000)+(300,6000000)++-}++data Maybe' a = Just' a | Nothing'++scanned :: Monad m => (x -> a -> x) -> x -> (x -> b) -> Stream (Of a) m r -> Stream (Of (a,b)) m r+scanned step begin done = loop Nothing' begin+ where+ loop !m !x stream = do + case stream of + Return r -> return r+ Effect mn -> Effect $ liftM (loop m x) mn+ Step (a :> rest) -> do+ case m of + Nothing' -> do + let !acc = step x a+ yield (a, done acc)+ loop (Just' a) acc rest+ Just' _ -> do+ let !acc = done (step x a)+ yield (a, acc) + loop (Just' a) (step x a) rest+{-# INLINABLE scanned #-}+++{-| Streams the number of seconds from the beginning of action+ + Thus, to mark times of user input we might write something like:++>>> S.toList $ S.take 3 $ S.zip S.seconds S.stdinLn +a<Enter>+b<Enter>+c<Enter>+[(0.0,"a"),(1.088711,"b"),(3.7289649999999996,"c")] :> ()+ + To restrict user input to some number of seconds, we might write:+ +>>> S.toList $ S.zipWith (flip const) (S.takeWhile (< 5) S.seconds) S.stdinLn+one<Enter>+two<Enter>+three<Enter>+four<Enter>+five<Enter>+["one","two","three","four","five"] :> ()++ -}+ +seconds :: Stream (Of Double) IO r+seconds = do + e <- lift $ next preseconds+ case e of+ Left r -> return r+ Right (t, rest) -> do+ yield 0+ map (subtract t) rest+ where + preseconds :: Stream (Of Double) IO r+ preseconds = do+ utc <- liftIO getCurrentTime+ map ((/1000000000) . nice utc) (repeatM getCurrentTime)+ where+ nice u u' = fromIntegral $ truncate (1000000000 * diffUTCTime u' u)++-- ---------------+-- sequence+-- ---------------++{-| Like the 'Data.List.sequence' but streaming. The result type is a+ stream of a\'s, /but is not accumulated/; the effects of the elements+ of the original stream are interleaved in the resulting stream. Compare:++> sequence :: Monad m => [m a] -> m [a]+> sequence :: Monad m => Stream (Of (m a)) m r -> Stream (Of a) m r++ This obeys the rule++-}+sequence :: Monad m => Stream (Of (m a)) m r -> Stream (Of a) m r+sequence = loop where+ loop stream = case stream of+ Return r -> Return r+ Effect m -> Effect $ liftM loop m+ Step (ma :> rest) -> Effect $ do+ a <- ma+ return (Step (a :> loop rest))+{-# INLINABLE sequence #-}++-- ---------------+-- show+-- ---------------++show :: (Monad m, Show a) => Stream (Of a) m r -> Stream (Of String) m r+show = map Prelude.show+{-# INLINE show #-}+-- ---------------+-- sum +-- ---------------++-- | Fold a 'Stream' of numbers into their sum+sum_ :: (Monad m, Num a) => Stream (Of a) m () -> m a+sum_ = fold_ (+) 0 id+{-# INLINE sum_ #-}++{-| Fold a 'Stream' of numbers into their sum with the return value++> mapped S.sum :: Stream (Stream (Of Int)) m r -> Stream (Of Int) m r+++>>> S.sum $ each [1..10]+55 :> ()++>>> (n :> rest) <- S.sum $ S.splitAt 3 $ each [1..10]+>>> print n+6+>>> (m :> rest') <- S.sum $ S.splitAt 3 rest+>>> print m+15+>>> S.print rest'+7+8+9++-}+sum :: (Monad m, Num a) => Stream (Of a) m r -> m (Of a r)+sum = fold (+) 0 id+{-# INLINABLE sum #-}++-- ---------------+-- span+-- ---------------++-- | Stream elements until one fails the condition, return the rest.+span :: Monad m => (a -> Bool) -> Stream (Of a) m r + -> Stream (Of a) m (Stream (Of a) m r)+span pred = loop where+ loop str = case str of + Return r -> Return (Return r)+ Effect m -> Effect $ liftM loop m+ Step (a :> rest) -> if pred a + then Step (a :> loop rest)+ else Return (Step (a :> rest))+{-# INLINABLE span #-}++ +{-| Split a stream of elements wherever a given element arises.+ The action is like that of 'Prelude.words'. ++>>> S.stdoutLn $ mapped S.toList $ S.split ' ' $ each "hello world "+hello+world++-}++split :: (Eq a, Monad m) =>+ a -> Stream (Of a) m r -> Stream (Stream (Of a) m) m r+split t = loop where+ loop stream = case stream of + Return r -> Return r+ Effect m -> Effect (liftM loop m)+ Step (a :> rest) -> + if a /= t+ then Step (fmap loop (yield a >> break (== t) rest))+ else loop rest+{-#INLINABLE split #-}++{-| Split a succession of layers after some number, returning a streaming or+-- effectful pair. This function is the same as the 'splitsAt' exported by the+-- @Streaming@ module, but since this module is imported qualified, it can +-- usurp a Prelude name. It specializes to:++> splitAt :: (Monad m, Functor f) => Int -> Stream (Of a) m r -> Stream (Of a) m (Stream (Of a) m r)++-}+splitAt :: (Monad m, Functor f) => Int -> Stream f m r -> Stream f m (Stream f m r)+splitAt = splitsAt+{-# INLINE splitAt #-}+++-- ---------------+-- take+-- ---------------++{-| End a stream after n elements; the original return value is thus lost.+ 'splitAt' preserves this information. Note that, like @splitAt@, this+ function is functor-general, so that, for example, you can @take@ not+ just a number of items from a stream of elements, but a number + of substreams and the like.++>>> S.toList $ S.take 3 $ each "pennsylvania"+"pen" :> ()++>>> total <- S.sum_ $ S.take 3 S.readLn :: IO Int+1<Enter>+10<Enter>+100<Enter>+>>> print total+111++-}++take :: (Monad m, Functor f) => Int -> Stream f m r -> Stream f m ()+take = loop where+ loop 0 p = return ()+ loop n p = + case p of Step fas -> Step (fmap (loop (n-1)) fas)+ Effect m -> Effect (liftM (loop n) m)+ Return r -> Return ()+{-# INLINABLE take #-}++-- ---------------+-- takeWhile+-- ---------------++{-| End stream when an element fails a condition; the original return value is lost.+ By contrast 'span' preserves this information.+++-}+takeWhile :: Monad m => (a -> Bool) -> Stream (Of a) m r -> Stream (Of a) m ()+takeWhile pred = loop where+ loop str = case str of + Step (a :> as) -> when (pred a) (Step (a :> loop as))+ Effect m -> Effect (liftM loop m)+ Return r -> Return ()+{-# INLINE takeWhile #-}+++{-| Convert an effectful 'Stream (Of a)' into a list of @as@++ Note: Needless to say, this function does not stream properly.+ It is basically the same as 'mapM' which, like 'replicateM',+ 'sequence' and similar operations on traversable containers+ is a leading cause of space leaks.+ +-}+toList_ :: Monad m => Stream (Of a) m () -> m [a]+toList_ = fold_ (\diff a ls -> diff (a: ls)) id (\diff -> diff [])+{-# INLINE toList_ #-}+++{-| Convert an effectful 'Stream' into a list alongside the return value++> mapped toListM :: Stream (Stream (Of a)) m r -> Stream (Of [a]) m +-}+toList :: Monad m => Stream (Of a) m r -> m (Of [a] r)+toList = fold (\diff a ls -> diff (a: ls)) id (\diff -> diff [])+{-# INLINE toList #-}+++{-| Inspect the first item in a stream of elements, without a return value. + @uncons@ provides convenient exit into another streaming type:++> IOStreams.unfoldM uncons :: Stream (Of a) IO b -> IO (InputStream a)+> Conduit.unfoldM uncons :: Stream (Of a) m r -> Conduit.Source m a++-}+uncons :: Monad m => Stream (Of a) m () -> m (Maybe (a, Stream (Of a) m ()))+uncons = loop where+ loop stream = case stream of+ Return () -> return Nothing+ Effect m -> m >>= loop+ Step (a :> rest) -> return (Just (a,rest))+{-# INLINABLE uncons #-}+++{-| Build a @Stream@ by unfolding steps starting from a seed. ++ The seed can of course be anything, but this is one natural way + to consume a @pipes@ 'Pipes.Producer'. Consider:++>>> S.stdoutLn $ S.take 2 $ S.unfoldr P.next P.stdinLn+hello<Enter>+hello+goodbye<Enter>+goodbye++>>> S.stdoutLn $ S.unfoldr P.next (P.stdinLn P.>-> P.take 2)+hello<Enter>+hello+goodbye<Enter>+goodbye++>>> S.effects $ S.unfoldr P.next (P.stdinLn P.>-> P.take 2 P.>-> P.stdoutLn)+hello<Enter>+hello+goodbye<Enter>+goodbye++-}+unfoldr :: Monad m + => (s -> m (Either r (a, s))) -> s -> Stream (Of a) m r+unfoldr step = loop where+ loop s0 = Effect (do + e <- step s0+ case e of+ Left r -> return (Return r)+ Right (a,s) -> return (Step (a :> loop s)))+{-# INLINABLE unfoldr #-}++-- ---------------------------------------+-- with+-- ---------------------------------------++{-| Replace each element in a stream of individual Haskell values (a @Stream (Of a) m r@) with an associated 'functorial' step. + +> for str f = concats (with str f) +> with str f = for str (yields . f)+> with str f = maps (\(a:>r) -> r <$ f a) str++>>> with (each [1..3]) (yield . show) & intercalates (yield "--") & S.stdoutLn+1+--+2+--+3+ -}+with :: (Monad m, Functor f) => Stream (Of a) m r -> (a -> f x) -> Stream f m r+with s f = loop s where+ loop str = case str of + Return r -> Return r+ Effect m -> Effect (liftM loop m)+ Step (a :> rest) -> Step (loop rest <$ f a)+{-#INLINABLE with #-}+ +-- ---------------------------------------+-- yield+-- ---------------------------------------++{-| A singleton stream++>>> stdoutLn $ yield "hello"+hello++>>> S.sum $ do {yield 1; yield 2}+3+ +>>> let prompt = putStrLn "Enter a number:" +>>> let number = lift (prompt >> readLn) >>= yield :: Stream (Of Int) IO ()+>>> S.toList $ do {number; number; number}+Enter a number:+1+Enter a number:+2+Enter a number:+3+[1,2,3] :> ()++-}++yield :: Monad m => a -> Stream (Of a) m ()+yield a = Step (a :> Return ())+{-# INLINE yield #-}++-- | Zip two 'Streams's +zip :: Monad m+ => (Stream (Of a) m r)+ -> (Stream (Of b) m r)+ -> (Stream (Of (a,b)) m r)+zip = zipWith (,)+{-# INLINE zip #-}++-- | Zip two 'Streams's using the provided combining function+zipWith :: Monad m+ => (a -> b -> c)+ -> (Stream (Of a) m r)+ -> (Stream (Of b) m r)+ -> (Stream (Of c) m r)+zipWith f = loop+ where+ loop str0 str1 = case str0 of+ Return r -> Return r+ Effect m -> Effect $ liftM (\str -> loop str str1) m + Step (a :> rest0) -> case str1 of+ Return r -> Return r+ Effect m -> Effect $ liftM (loop str0) m+ Step (b :> rest1) -> Step (f a b :>loop rest0 rest1)+{-# INLINABLE zipWith #-}+++-- | Zip three 'Stream's with a combining function+zipWith3 :: Monad m =>+ (a -> b -> c -> d)+ -> Stream (Of a) m r+ -> Stream (Of b) m r+ -> Stream (Of c) m r+ -> Stream (Of d) m r+zipWith3 op = loop where+ loop str0 str1 str2 = do+ e0 <- lift (next str0)+ case e0 of + Left r0 -> return r0+ Right (a0,rest0) -> do + e1 <- lift (next str1)+ case e1 of+ Left r1 -> return r1+ Right (a1,rest1) -> do + e2 <- lift (next str2)+ case e2 of+ Left r2 -> return r2+ Right (a2,rest2) -> do + yield (op a0 a1 a2)+ loop rest0 rest1 rest2+{-# INLINABLE zipWith3 #-} + + +-- | Zip three streams together +zip3 :: Monad m+ => (Stream (Of a) m r)+ -> (Stream (Of b) m r)+ -> (Stream (Of c) m r)+ -> (Stream (Of (a,b,c)) m r)+zip3 = zipWith3 (,,)+{-# INLINABLE zip3 #-}++-- --------------+-- IO fripperies +-- --------------++{-| View standard input as a 'Stream (Of String) m r'. 'stdoutLn', by+ contrast, renders a 'Stream (Of String) m r' to standard output. The names+ follow @Pipes.Prelude@++>>> stdoutLn stdinLn +hello<Enter>+hello+world<Enter>+world+^CInterrupted.+++>>> stdoutLn $ S.map reverse stdinLn +hello<Enter>+olleh+world<Enter>+dlrow+^CInterrupted.++-}+stdinLn :: MonadIO m => Stream (Of String) m ()+stdinLn = fromHandle IO.stdin+{-# INLINABLE stdinLn #-}++{-| Read values from 'IO.stdin', ignoring failed parses++>>> S.sum_ $ S.take 2 S.readLn :: IO Int+10<Enter>+12<Enter>+22++>>> S.toList $ S.take 3 (S.readLn :: Stream (Of Int) IO ())+1<Enter>+2<Enter>+1@#$%^&*\<Enter>+3<Enter>+[1,2,3] :> ()+++-}++readLn :: (MonadIO m, Read a) => Stream (Of a) m ()+readLn = for stdinLn $ \str -> case readMaybe str of + Nothing -> return ()+ Just n -> yield n+{-# INLINABLE readLn #-}+++{-| Read 'String's from a 'IO.Handle' using 'IO.hGetLine'++ Terminates on end of input++>>> IO.withFile "/usr/share/dict/words" IO.ReadMode $ S.stdoutLn . S.take 3 . S.drop 50000 . S.fromHandle+deflagrator+deflate+deflation++-}+fromHandle :: MonadIO m => IO.Handle -> Stream (Of String) m ()+fromHandle h = go+ where+ go = do+ eof <- liftIO $ IO.hIsEOF h+ unless eof $ do+ str <- liftIO $ IO.hGetLine h+ yield str+ go+{-# INLINABLE fromHandle #-} ++{-| Write a succession of strings to a handle as separate lines.++>>> S.toHandle IO.stdout $ each $ words "one two three"+one+two+three+-}+toHandle :: MonadIO m => IO.Handle -> Stream (Of String) m r -> m r+toHandle handle = loop where+ loop str = case str of+ Return r -> return r+ Effect m -> m >>= loop + Step (s :> rest) -> do + liftIO (IO.hPutStrLn handle s)+ loop rest+{-# INLINABLE toHandle #-} ++{-| Print the elements of a stream as they arise.++>>> S.print $ S.take 2 S.stdinLn +hello+"hello"+world+"world"+>>> ++-}+print :: (MonadIO m, Show a) => Stream (Of a) m r -> m r+print = loop where+ loop stream = case stream of + Return r -> return r + Effect m -> m >>= loop+ Step (a :> rest) -> do + liftIO (Prelude.print a)+ loop rest+++{-| Write 'String's to 'IO.stdout' using 'putStrLn'; terminates on a broken output pipe+ (This operation is modelled on 'Pipes.Prelude.stdoutLn').++>>> S.stdoutLn $ S.take 3 $ S.each $ words "one two three four five"+one+two+three+-}+stdoutLn :: MonadIO m => Stream (Of String) m () -> m ()+stdoutLn = loop+ where+ loop stream = case stream of + Return _ -> return () + Effect m -> m >>= loop+ Step (s :> rest) -> do+ x <- liftIO $ try (putStrLn s)+ case x of+ Left (G.IOError { G.ioe_type = G.ResourceVanished+ , G.ioe_errno = Just ioe })+ | Errno ioe == ePIPE+ -> return ()+ Left e -> liftIO (throwIO e)+ Right () -> loop rest+{-# INLINABLE stdoutLn #-}+++++{-| Write 'String's to 'IO.stdout' using 'putStrLn'++ This does not handle a broken output pipe, but has a polymorphic return+ value, which makes this possible:++>>> rest <- S.stdoutLn' $ S.show $ S.splitAt 3 (each [1..5])+1+2+3+>>> S.print rest+4+5++-}++stdoutLn' :: MonadIO m => Stream (Of String) m r -> m r+stdoutLn' = loop where + loop stream = case stream of + Return r -> return r + Effect m -> m >>= loop+ Step (s :> rest) -> liftIO (putStrLn s) >> loop rest+{-# INLINE stdoutLn' #-}++{-| Read a series of strings as lines to a file.++>>> runResourceT $ S.writeFile "lines.txt" $ S.take 2 S.stdinLn+hello<Enter>+world<Enter>+>>> runResourceT $ S.print $ S.readFile "lines.txt" +"hello"+"world"++ 'runResourceT', as it is used here, means something like 'closing_handles';+ it makes it possible to write convenient, fairly sensible versions of + 'readFile', 'writeFile' and 'appendFile'. Its use is explained + <https://www.fpcomplete.com/user/snoyberg/library-documentation/resourcet here>.++-}++readFile :: MonadResource m => FilePath -> Stream (Of String) m ()+readFile f = bracketStream (IO.openFile f IO.ReadMode) (IO.hClose) fromHandle++{-| Write a series of strings as lines to a file. The handle is crudely + managed with 'ResourceT':++>>> runResourceT $ S.writeFile "lines.txt" $ S.take 2 S.stdinLn+hello<Enter>+world<Enter>+>>> runResourceT $ S.print $ S.readFile "lines.txt" +"hello"+"world"++-}+writeFile :: MonadResource m => FilePath -> Stream (Of String) m r -> m r+writeFile f str = do + (key, handle) <- allocate (IO.openFile f IO.WriteMode) (IO.hClose) + r <- toHandle handle str+ release key+ return r++-- -- * Producers+-- -- $producers+-- stdinLn -- +-- , readLn -- +-- , fromHandle -- +-- , repeatM -- +-- , replicateM --+--+-- -- * Consumers+-- -- $consumers+-- , stdoutLn --+-- , stdoutLn' --+-- , mapM_ --+-- , print -- +-- , toHandle --+-- , effects --+--+-- -- * Pipes+-- -- $pipes+-- , map -- +-- , mapM --+-- , sequence -- +-- , mapFoldable -- +-- , filter --+-- , filterM --+-- , take --+-- , takeWhile --+-- , takeWhile' --+-- , drop --+-- , dropWhile -- +-- , concat --+-- , elemIndices+-- , findIndices+-- , scan --+-- , scanM --+-- , chain --+-- , read --+-- , show -- +-- , seq --+--+-- -- * Folds+-- -- $folds+-- , fold --+-- , fold' --+-- , foldM --+-- , foldM' --+-- , all+-- , any+-- , and+-- , or+-- , elem+-- , notElem+-- , find+-- , findIndex+-- , head+-- , index+-- , last+-- , length+-- , maximum+-- , minimum+-- , null+-- , sum --+-- , product --+-- , toList --+-- , toListM --+-- , toListM' --+--+-- -- * Zips+-- , zip --+-- , zipWith --+--++distinguish :: (a -> Bool) -> Of a r -> Sum (Of a) (Of a) r+distinguish predicate (a :> b) = if predicate a then InR (a :> b) else InL (a :> b)+{-#INLINE distinguish #-}++sumToEither ::Sum (Of a) (Of b) r -> Of (Either a b) r +sumToEither s = case s of + InL (a :> r) -> Left a :> r + InR (b :> r) -> Right b :> r+{-#INLINE sumToEither #-}++eitherToSum :: Of (Either a b) r -> Sum (Of a) (Of b) r+eitherToSum s = case s of + Left a :> r -> InL (a :> r)+ Right b :> r -> InR (b :> r)+{-#INLINE eitherToSum #-}++composeToSum :: Compose (Of Bool) f r -> Sum f f r+composeToSum x = case x of + Compose (True :> f) -> InR f+ Compose (False :> f) -> InL f+{-#INLINE composeToSum #-}++sumToCompose :: Sum f f r -> Compose (Of Bool) f r +sumToCompose x = case x of+ InR f -> Compose (True :> f) + InL f -> Compose (False :> f)+{-#INLINE sumToCompose #-}++{-| Store the result of any suitable fold over a stream, keeping the stream for+ further manipulation. @store f = f . duplicate@ :++>>> S.print $ S.store S.product $ each [1..4]+1+2+3+4+24 :> ()++>>> S.print $ S.store S.sum $ S.store S.product $ each [1..4]+1+2+3+4+10 :> (24 :> ())++ Here the sum (10) and the product (24) have been \'stored\' for use when + finally we have traversed the stream with 'print' . Needless to say,+ a second 'pass' is excluded conceptually, so the + folds that you apply successively with @store@ are performed + simultaneously, and in constant memory -- as they would be if, + say, you linked them together with @Control.Fold@:++>>> L.impurely S.foldM (liftA3 (\a b c -> (b,c)) (L.sink print) (L.generalize L.sum) (L.generalize L.product)) $ each [1..4]+1+2+3+4+(10,24) :> ()++ Fusing folds after the fashion of @Control.Foldl@ will generally be a bit faster+ than the corresponding succession of uses of 'store', but by+ constant factor that will be completely dwarfed when any IO is at issue.++ But 'store' / 'duplicate' is /much/ more powerful, as you can see by reflecting on + uses like this:++>>> S.sum $ S.store (S.sum . mapped S.product . chunksOf 2) $ S.store (S.product . mapped S.sum . chunksOf 2 )$ each [1..6]+21 :> (44 :> (231 :> ()))++ It will be clear that this cannot be reproduced with any combination of lenses, + @Control.Fold@ folds, or the like. (See also the discussion of 'duplicate'.)++ 'store' is intended to be used at types like these++> storeM :: (Monad m => Stream (Of a) m r -> m (Of b r)) +> -> (Monad n => Stream (Of a) n r -> Stream (Of a) n (Of b r))+> storeM = store+>+> storeMIO :: (MonadIO m => Stream (Of a) m r -> m (Of b r)) +> -> ( MonadIO n => Stream (Of a) n r -> Stream (Of a) n (Of b r)+> storeMIO = store++ And similarly for other constraints that @Stream (Of a)@ inherits, + like 'MonadResource'. Thus I can filter and write to one file, but + nub and write to another: ++>>> runResourceT $ (S.writeFile "hello2.txt" . S.nub) $ store (S.writeFile "hello.txt" . S.filter (/= "world")) $ each ["hello", "world", "goodbye", "world"]+>>> :! cat hello.txt+hello+goodbye+>>> :! cat hello2.txt+hello+world+goodbye+++-}+store+ :: Monad m =>+ (Stream (Of a) (Stream (Of a) m) r -> t) -> Stream (Of a) m r -> t+store f x = f (duplicate x)+{-#INLINE store #-}++{-| Duplicate the content of stream, so that it can be acted on twice in different ways, + but without breaking streaming. Thus, given: ++>>> S.print $ each ["one","two"]+"one"+"two"+>>> S.stdoutLn $ each ["one","two"]+one+two++ I can as well do:++>>> S.print $ S.stdoutLn $ S.duplicate $ each ["one","two"]+one+"one"+two+"two"++ Where the actions you are contemplating are each simple folds over + the elements, or a selection of elements, then the coupling of the + folds is often more straightforwardly effected with `Control.Foldl`, + e.g.++>>> L.purely S.fold (liftA2 (,) L.sum L.product) $ each [1..10]+(55,3628800) :> ()++ rather than++>>> S.sum $ S.product . S.duplicate $ each [1..10]+55 :> (3628800 :> ())++ A @Control.Foldl@ fold can be altered to act on a selection of elements by + using 'Control.Foldl.handles' on an appropriate lens. Some such + manipulations are simpler and more 'Data.List'-like, using 'duplicate':++>>> L.purely S.fold (liftA2 (,) (L.handles (filtered odd) L.sum) (L.handles (filtered even) L.product)) $ each [1..10]+(25,3840) :> ()++ becomes++>>> S.sum $ S.filter odd $ S.product $ S.filter even $ S.duplicate $ each [1..10]+25 :> (3840 :> ())++ or using 'store' ++>>> S.sum $ S.filter odd $ S.store (S.product . S.filter even) $ each [1..10]+25 :> (3840 :> ())++ But anything that fold of a @Stream (Of a) m r@ into e.g. an @m (Of b r)@+ that has a constraint on @m@ that is carried over into @Stream f m@ - + e.g. @Monad@, @MonadIO@, @MonadResource@, etc. can be used on the stream.+ Thus, I can fold over different groupings of the original stream:++>>> (S.toList . mapped S.toList . chunksOf 5) $ (S.toList . mapped S.toList . chunksOf 3) $ S.duplicate $ each [1..10]+[[1,2,3,4,5],[6,7,8,9,10]] :> ([[1,2,3],[4,5,6],[7,8,9],[10]] :> ())++ The procedure can be iterated as one pleases, as one can see from this (otherwise unadvisable!) example:++>>> (S.toList . mapped S.toList . chunksOf 4) $ (S.toList . mapped S.toList . chunksOf 3) $ S.duplicate $ (S.toList . mapped S.toList . chunksOf 2) $ S.duplicate $ each [1..12]+[[1,2,3,4],[5,6,7,8],[9,10,11,12]] :> ([[1,2,3],[4,5,6],[7,8,9],[10,11,12]] :> ([[1,2],[3,4],[5,6],[7,8],[9,10],[11,12]] :> ()))++-}+duplicate+ :: Monad m =>+ Stream (Of a) m r -> Stream (Of a) (Stream (Of a) m) r+duplicate = loop where+ loop str = case str of+ Return r -> Return r+ Effect m -> Effect (liftM loop (lift m))+ Step (a :> rest) -> Step (a :> Effect (Step (a :> Return (loop rest))))+{-#INLINABLE duplicate#-}++{-| The type++> Data.List.unzip :: [(a,b)] -> ([a],[b])++ might lead us to expect ++> Streaming.unzip :: Stream (Of (a,b)) m r -> Stream (Of a) m (Stream (Of b) m r)+ + which would not stream. Of course, neither does 'Data.List.unzip'++-}+unzip :: Monad m => Stream (Of (a,b)) m r -> Stream (Of a) (Stream (Of b) m) r+unzip = loop where+ loop str = case str of + Return r -> Return r+ Effect m -> Effect (liftM loop (lift m))+ Step ((a,b):> rest) -> Step (a :> Effect (Step (b :> Return (loop rest))))+{-#INLINABLE unzip #-}+++-- "fold/map" forall step begin done f str .+-- fold step begin done (map f str) = fold (\x a -> step x $! f a) begin done str;+--+-- "fold/filter" forall step begin done pred str .+-- fold step begin done (filter pred str) = fold (\x a -> if pred a then step x a else x) begin done str;+--+-- "scan/map" forall step begin done f str .+-- scan step begin done (map f str) = scan (\x a -> step x $! f a) begin done str+--
streaming.cabal view
@@ -1,16 +1,45 @@ name: streaming-version: 0.1.2.2+version: 0.1.3.0 cabal-version: >=1.10 build-type: Simple synopsis: an elementary streaming prelude and a general monad transformer for streaming applications. -description: @Streaming.Prelude@ exports an elementary streaming prelude; @Streaming@ exports a free monad transformer - optimized for streaming applications and replacing @FreeT@. See the +description: @Streaming.Prelude@ exports an elementary streaming prelude relating to + an elementary source\/generator\/producer type, @Stream (Of a) m r@. + @Streaming@ exports a much more general type, @Stream f m r@, which+ can be used to 'stream' successive distinct steps characterized by any + functor @f@, though we are here interested only in a limited range of + cases. + .+ The streaming-io libraries have various devices for dealing+ with effectful variants of @[a]@ or @([a],r)@. But it is only with+ the general type @Stream f m r@, or some equivalent, + that one can hope to stream streams, as one makes lists of + lists in the Haskell @Prelude@ and @Data.List@. Once one sees + the necessity of some such type if we are to+ express a properly streaming equivalent of e.g.+ + > groups :: Ord a => [a] -> [[a]]+ > chunksOf :: Int -> [a] -> [[a]]+ + and the like, then one will also see that, with it, + one is already in possession of a complete+ elementary streaming library. The present @Streaming.Prelude@ is the+ simplest streaming library that can replicate anything like the + API of the @Prelude@ and @Data.List@. + .+ The emphasis of the library is on interoperation; for+ the rest its advantages are: extreme simplicity and re-use of + intuitions the user has gathered from mastery of @Prelude@ and+ @Data.List@. The two conceptual pre-requisites are some + comprehension of monad transformers and some familiarity + with \'rank 2 types\'.+ . + See the <https://hackage.haskell.org/package/streaming#readme readme> below- for an explanation. Elementary usage can be divined from the ghci examples in - @Streaming.Prelude@ and from the remarks somewhat theoretical- <https://hackage.haskell.org/package/streaming#readme readme>- below, including the examples linked there. Note also the + for an explanation, including the examples linked there. Elementary usage can be divined from the ghci examples in + @Streaming.Prelude@ and perhaps from this rough beginning of a + <https://github.com/michaelt/streaming-tutorial/blob/master/tutorial.md tutorial> Note also the <https://hackage.haskell.org/package/streaming-bytestring streaming bytestring> and <https://hackage.haskell.org/package/streaming-utils streaming utils> @@ -36,15 +65,15 @@ <https://hackage.haskell.org/package/streaming#readme readme> below. .- Here are some results for an - <https://gist.github.com/michaelt/f19bef01423b17f29ffd expansion> - of the little + Here are the results of some+ <https://gist.github.com/michaelt/f19bef01423b17f29ffd microbenchmarks> + based on the <https://github.com/ekmett/machines/blob/master/benchmarks/Benchmarks.hs benchmarks> included in the machines package: . <<http://i.imgur.com/sSG5MvH.png>> .- + license: BSD3 license-file: LICENSE@@ -77,9 +106,13 @@ , mtl >=2.1 && <2.3 , mmorph >=1.0 && <1.2 , transformers >=0.4 && <0.5+ , transformers-base , bytestring , time-+ , resourcet+ , exceptions+ , containers+ default-language: Haskell2010