-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Streaming, dataflow programming and declarative concurrency -- -- For upgrading to streamly-0.9.0+ please read the Streamly-0.9.0 -- upgrade guide. -- -- Streamly is a standard library for Haskell that focuses on C-like -- performance, modular combinators, and streaming data flow model. -- Streamly consists of two packages, the streamly-core package -- provides functionality that depends only on boot libraries, and the -- streamly package provides additional functionality like -- concurrency, time, lifted exceptions, and networking. For unified -- documentation visit the streamly website. -- -- Streamly provides unified, modular building blocks to build -- high-performance, concurrent, scalable applications in Haskell. Stream -- fusion optimizations in streamly enable exceptional modularity with -- high performance comparable to C. Streamly complements the Haskell -- base package, supplying additional functionality to quickly -- build general-purpose applications in Haskell. For high-level -- functionality built over streamly like streaming OS processes, shell -- programming, GNU coreutils, statistics, and compression libraries -- please see the streamly ecosystem packages. -- -- Performance with modularity: -- --
-- >>> import Data.Functor.Identity (Identity, runIdentity) -- -- >>> s = Stream.fromList [1..10] :: SerialT Identity Int -- -- >>> s1 = Stream.hoist (return . runIdentity) s :: SerialT IO Int -- -- >>> Stream.fold Array.write s1 :: IO (Array Int) -- fromList [1,2,3,4,5,6,7,8,9,10] ---- -- unsafePerformIO can be used to get a pure API from IO, as -- long as you know it is safe to do so: -- --
-- >>> import System.IO.Unsafe (unsafePerformIO) -- -- >>> unsafePerformIO $ Stream.fold Array.write s1 :: Array Int -- fromList [1,2,3,4,5,6,7,8,9,10] ---- -- To apply a transformation to an array use read to unfold the -- array into a stream, apply a transformation on the stream and then use -- write to fold it back to an array. -- -- This module is designed to be imported qualified: -- --
-- import qualified Streamly.Data.Array as Array ---- -- For experimental APIs see Streamly.Internal.Data.Array. -- | Deprecated: Please use Streamly.Data.Array module from the -- streamly-core package. module Streamly.Data.Array.Foreign data Array a fromListN :: Unbox a => Int -> [a] -> Array a fromList :: Unbox a => [a] -> Array a writeN :: forall (m :: Type -> Type) a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a) write :: forall (m :: Type -> Type) a. (MonadIO m, Unbox a) => Fold m a (Array a) writeLastN :: forall a (m :: Type -> Type). (Storable a, Unbox a, MonadIO m) => Int -> Fold m a (Array a) toList :: Unbox a => Array a -> [a] read :: forall (m :: Type -> Type) a. (Monad m, Unbox a) => Array a -> Stream m a readRev :: forall (m :: Type -> Type) a. (Monad m, Unbox a) => Array a -> Stream m a cast :: forall a b. Unbox b => Array a -> Maybe (Array b) asBytes :: Array a -> Array Word8 length :: Unbox a => Array a -> Int getIndex :: Unbox a => Int -> Array a -> Maybe a instance Control.DeepSeq.NFData (Streamly.Internal.Data.Array.Type.Array a) instance Control.DeepSeq.NFData1 Streamly.Internal.Data.Array.Type.Array -- | Deprecated: Please use Streamly.Data.Fold module from the -- streamly-core package. module Streamly.Data.Fold.Tee newtype Tee (m :: Type -> Type) a b Tee :: Fold m a b -> Tee (m :: Type -> Type) a b [unTee] :: Tee (m :: Type -> Type) a b -> Fold m a b toFold :: forall (m :: Type -> Type) a b. Tee m a b -> Fold m a b -- | Please do not add any general routines in this. It should be renamed -- appropriately. module Streamly.Internal.Control.Concurrent -- | A monad that can perform concurrent or parallel IO operations. Streams -- that can be composed concurrently require the underlying monad to be -- MonadAsync. type MonadAsync m = (MonadIO m, MonadBaseControl IO m, MonadThrow m) type MonadRunInIO m = (MonadIO m, MonadBaseControl IO m) newtype RunInIO (m :: Type -> Type) RunInIO :: (forall b. () => m b -> IO (StM m b)) -> RunInIO (m :: Type -> Type) [runInIO] :: RunInIO (m :: Type -> Type) -> forall b. () => m b -> IO (StM m b) -- | When we run computations concurrently, we completely isolate the state -- of the concurrent computations from the parent computation. The -- invariant is that we should never be running two concurrent -- computations in the same thread without using the runInIO function. -- Also, we should never be running a concurrent computation in the -- parent thread, otherwise it may affect the state of the parent which -- is against the defined semantics of concurrent execution. askRunInIO :: MonadRunInIO m => m (RunInIO m) withRunInIO :: MonadRunInIO m => ((forall a. m a -> IO (StM m a)) -> IO (StM m b)) -> m b withRunInIONoRestore :: MonadRunInIO m => ((forall a. m a -> IO (StM m a)) -> IO b) -> m b -- | Construct a m computation from the monadic state of -- m that is returned from a RunInBase function. -- -- Instances should satisfy: -- --
-- liftBaseWith (\runInBase -> runInBase m) >>= restoreM = m ---- -- restoreM is usually not implemented directly, but -- using defaultRestoreM. restoreM :: MonadBaseControl b m => StM m a -> m a module Streamly.Internal.Control.ForkLifted -- | Fork a thread to run the given computation, installing the provided -- exception handler. Lifted to any monad with 'MonadRunInIO m' -- capability. -- -- TODO: the RunInIO argument can be removed, we can directly pass the -- action as "mrun action" instead. doFork :: MonadRunInIO m => m () -> RunInIO m -> (SomeException -> IO ()) -> m ThreadId -- | Similar to doFork, but has a "bound" boolean parameter for -- specifying whether forkOS should be used instead of -- rawForkIO. doForkWith :: MonadRunInIO m => Bool -> m () -> RunInIO m -> (SomeException -> IO ()) -> m ThreadId -- | fork lifted to any monad with 'MonadBaseControl IO m' -- capability. fork :: MonadRunInIO m => m () -> m ThreadId -- | Fork a thread that is automatically killed as soon as the reference to -- the returned threadId is garbage collected. forkManaged :: MonadRunInIO m => m () -> m ThreadId module Streamly.Internal.Data.Atomics atomicModifyIORefCAS :: IORef a -> (a -> (a, b)) -> IO b atomicModifyIORefCAS_ :: IORef t -> (t -> t) -> IO () writeBarrier :: IO () storeLoadBarrier :: IO () module Streamly.Internal.Data.Channel -- | This is a magic number and it is overloaded, and used at several -- places to achieve batching: -- --
-- >>> import Data.HashMap.Strict (HashMap, fromList) -- -- >>> import qualified Streamly.Data.Fold.Prelude as Fold -- -- >>> import qualified Streamly.Data.Stream as Stream ---- -- Consider a stream of key value pairs: -- --
-- >>> input = Stream.fromList [("k1",1),("k1",1.1),("k2",2), ("k2",2.2)] ---- -- Classify each key to a different hash bin and fold the bins: -- --
-- >>> classify = Fold.toHashMapIO fst (Fold.lmap snd Fold.toList) -- -- >>> Stream.fold classify input :: IO (HashMap String [Double]) -- fromList [("k2",[2.0,2.2]),("k1",[1.0,1.1])] ---- -- Pre-release toHashMapIO :: (MonadIO m, Hashable k, Ord k) => (a -> k) -> Fold m a b -> Fold m a (HashMap k b) -- | Deprecated: SVar is replaced by Channel. module Streamly.Internal.Data.SVar decrementYieldLimit :: SVar t m a -> IO Bool incrementYieldLimit :: SVar t m a -> IO () decrementBufferLimit :: SVar t m a -> IO () incrementBufferLimit :: SVar t m a -> IO () resetBufferLimit :: SVar t m a -> IO () data Work BlockWait :: NanoSecond64 -> Work PartialWorker :: Count -> Work ManyWorkers :: Int -> Count -> Work isBeyondMaxRate :: SVar t m a -> YieldRateInfo -> IO Bool estimateWorkers :: Limit -> Count -> Count -> NanoSecond64 -> NanoSecond64 -> NanoSecond64 -> LatencyRange -> Work updateYieldCount :: WorkerInfo -> IO Count -- | This is a magic number and it is overloaded, and used at several -- places to achieve batching: -- --
-- >>> input = Stream.delay 0.2 $ Stream.fromList [1..10] -- -- >>> Stream.fold (Fold.takeInterval 1.0 Fold.toList) input -- [1,2,3,4,5,6] ---- --
-- >>> f = Fold.takeInterval 0.5 Fold.toList -- -- >>> Stream.fold Fold.toList $ Stream.foldMany f input -- [[1,2,3,4],[5,6,7],[8,9,10]] ---- -- Stops when fold stops or when the timeout occurs. Note that -- the fold needs an input after the timeout to stop. For example, if no -- input is pushed to the fold until one hour after the timeout had -- occurred, then the fold will be done only after consuming that input. -- -- Pre-release takeInterval :: MonadAsync m => Double -> Fold m a b -> Fold m a b -- | Group the input stream into windows of n second each using the first -- fold and then fold the resulting groups using the second fold. -- --
-- >>> intervals = Fold.intervalsOf 0.5 Fold.toList Fold.toList -- -- >>> Stream.fold intervals $ Stream.delay 0.2 $ Stream.fromList [1..10] -- [[1,2,3,4],[5,6,7],[8,9,10]] ---- --
-- intervalsOf n split = many (takeInterval n split) ---- -- Pre-release intervalsOf :: MonadAsync m => Double -> Fold m a b -> Fold m b c -> Fold m a c data Channel m a b Channel :: IORef ([ChildEvent a], Int) -> Limit -> MVar () -> m [ChildEvent a] -> IORef ([ChildEvent b], Int) -> MVar () -> MVar () -> Maybe (IORef ()) -> SVarStats -> Bool -> ThreadId -> Channel m a b [outputQueue] :: Channel m a b -> IORef ([ChildEvent a], Int) [maxBufferLimit] :: Channel m a b -> Limit [outputDoorBell] :: Channel m a b -> MVar () [readOutputQ] :: Channel m a b -> m [ChildEvent a] [outputQueueFromConsumer] :: Channel m a b -> IORef ([ChildEvent b], Int) [outputDoorBellFromConsumer] :: Channel m a b -> MVar () [bufferSpaceDoorBell] :: Channel m a b -> MVar () [svarRef] :: Channel m a b -> Maybe (IORef ()) [svarStats] :: Channel m a b -> SVarStats [svarInspectMode] :: Channel m a b -> Bool [svarCreator] :: Channel m a b -> ThreadId newChannel :: MonadRunInIO m => (Config -> Config) -> Fold m a b -> m (Channel m a b) -- | An abstract type for specifying the configuration parameters of a -- Channel. Use Config -> Config modifier functions -- to modify the default configuration. See the individual modifier -- documentation for default values. data Config -- | Push values from a driver to a fold worker via a Channel. Before -- pushing a value to the Channel it polls for events received from the -- fold worker. If a stop event is received then it returns True -- otherwise false. Propagates exceptions received from the fold wroker. sendToWorker :: MonadAsync m => Channel m a b -> a -> m (Maybe b) -- | Poll for events sent by the fold worker to the fold driver. The fold -- consumer can send a Stop event or an exception. When a -- Stop is received this function returns True. If an -- exception is recieved then it throws the exception. checkFoldStatus :: MonadAsync m => Channel m a b -> m (Maybe b) dumpSVar :: Channel m a b -> IO String -- | Specify the maximum size of the buffer for storing the results from -- concurrent computations. If the buffer becomes full we stop spawning -- more concurrent tasks until there is space in the buffer. A value of 0 -- resets the buffer size to default, a negative value means there is no -- limit. The default value is 1500. -- -- CAUTION! using an unbounded maxBuffer value (i.e. a negative -- value) coupled with an unbounded maxThreads value is a recipe -- for disaster in presence of infinite streams, or very large streams. -- Especially, it must not be used when pure is used in -- ZipAsyncM streams as pure in applicative zip streams -- generates an infinite stream causing unbounded concurrent generation -- with no limit on the buffer or threads. maxBuffer :: Int -> Config -> Config -- | Spawn bound threads (i.e., spawn threads using forkOS instead -- of forkIO). The default value is False. -- -- Currently, this only takes effect only for concurrent folds. boundThreads :: Bool -> Config -> Config -- | Print debug information about the Channel when the stream -- ends. inspect :: Bool -> Config -> Config -- | Evaluate a fold asynchronously using a concurrent channel. The driver -- just queues the input stream values to the fold channel buffer and -- returns. The fold evaluates the queued values asynchronously. On -- finalization, parEval waits for the asynchronous fold to -- complete before it returns. parEval :: MonadAsync m => (Config -> Config) -> Fold m a b -> Fold m a b -- | A fold to write a stream to an SVar. Unlike toSVar this does -- not allow for concurrent evaluation of the stream, as the fold -- receives the input one element at a time, it just forwards the -- elements to the SVar. However, we can safely execute the fold in an -- independent thread, the SVar can act as a buffer decoupling the sender -- from the receiver. Also, we can have multiple folds running -- concurrently pusing the streams to the SVar. write :: MonadIO m => SVar t m a -> Maybe WorkerInfo -> Fold m a () -- | Like write, but applies a yield limit. writeLimited :: MonadIO m => SVar t m a -> Maybe WorkerInfo -> Fold m a () module Streamly.Internal.Data.Stream.MkType -- | Create a type with a zip-like applicative. -- --
-- >>> expr <- runQ (mkZipType "ZipStream" "zipApply" False) -- -- >>> putStrLn $ pprint expr -- newtype ZipStream m a -- = ZipStream (Stream.Stream m a) -- deriving Foldable -- mkZipStream :: Stream.Stream m a -> ZipStream m a -- mkZipStream = ZipStream -- unZipStream :: ZipStream m a -> Stream.Stream m a -- unZipStream (ZipStream strm) = strm -- deriving instance IsList (ZipStream Identity a) -- deriving instance a ~ -- GHC.Types.Char => IsString (ZipStream Identity a) -- deriving instance GHC.Classes.Eq a => Eq (ZipStream Identity a) -- deriving instance GHC.Classes.Ord a => Ord (ZipStream Identity a) -- instance Show a => Show (ZipStream Identity a) -- where {{-# INLINE show #-}; show (ZipStream strm) = show strm} -- instance Read a => Read (ZipStream Identity a) -- where {{-# INLINE readPrec #-}; readPrec = fmap ZipStream readPrec} -- instance Monad m => Functor (ZipStream m) -- where {{-# INLINE fmap #-}; -- fmap f (ZipStream strm) = ZipStream (fmap f strm)} -- instance Monad m => Applicative (ZipStream m) -- where {{-# INLINE pure #-}; -- pure = ZipStream . Stream.repeat; -- {-# INLINE (<*>) #-}; -- (<*>) (ZipStream strm1) (ZipStream strm2) = ZipStream (zipApply strm1 strm2)} --mkZipType :: String -> String -> Bool -> Q [Dec] -- | Create a type with specific stream combination properties. -- --
-- >>> expr <- runQ (mkCrossType "Parallel" "parBind" True) -- -- >>> putStrLn $ pprint expr -- newtype Parallel m a = Parallel (Stream.Stream m a) -- mkParallel :: Stream.Stream m a -> Parallel m a -- mkParallel = Parallel -- unParallel :: Parallel m a -> Stream.Stream m a -- unParallel (Parallel strm) = strm -- instance Monad m => Functor (Parallel m) -- where {{-# INLINE fmap #-}; -- fmap f (Parallel strm) = Parallel (fmap f strm)} -- instance Stream.MonadAsync m => Monad (Parallel m) -- where {{-# INLINE (>>=) #-}; -- (>>=) (Parallel strm1) f = let f1 a = unParallel (f a) -- in Parallel (parBind strm1 f1)} -- instance Stream.MonadAsync m => Applicative (Parallel m) -- where {{-# INLINE pure #-}; -- pure = Parallel . Stream.fromPure; -- {-# INLINE (<*>) #-}; -- (<*>) = ap} -- instance (Monad (Parallel m), MonadIO m) => MonadIO (Parallel m) -- where {{-# INLINE liftIO #-}; -- liftIO = Parallel . (Stream.fromEffect . liftIO)} -- instance (Monad (Parallel m), -- MonadThrow m) => MonadThrow (Parallel m) -- where {{-# INLINE throwM #-}; -- throwM = Parallel . (Stream.fromEffect . throwM)} --mkCrossType :: String -> String -> Bool -> Q [Dec] -- | Monads in which IO computations may be embedded. Any monad -- built by applying a sequence of monad transformers to the IO -- monad will be an instance of this class. -- -- Instances should satisfy the following laws, which state that -- liftIO is a transformer of monads: -- -- class Monad m => MonadIO (m :: Type -> Type) -- | Lift a computation from the IO monad. This allows us to run IO -- computations in any monadic stack, so long as it supports these kinds -- of operations (i.e. IO is the base monad for the stack). -- --
-- import Control.Monad.Trans.State -- from the "transformers" library -- -- printState :: Show s => StateT s IO () -- printState = do -- state <- get -- liftIO $ print state ---- -- Had we omitted liftIO, we would have ended up with -- this error: -- --
-- • Couldn't match type ‘IO’ with ‘StateT s IO’ -- Expected type: StateT s IO () -- Actual type: IO () ---- -- The important part here is the mismatch between StateT s IO -- () and IO (). -- -- Luckily, we know of a function that takes an IO a and -- returns an (m a): liftIO, enabling us to run -- the program and see the expected results: -- --
-- > evalStateT printState "hello" -- "hello" -- -- > evalStateT printState 3 -- 3 --liftIO :: MonadIO m => IO a -> m a -- | A class for monads in which exceptions may be thrown. -- -- Instances should obey the following law: -- --
-- throwM e >> x = throwM e ---- -- In other words, throwing an exception short-circuits the rest of the -- monadic computation. class Monad m => MonadThrow (m :: Type -> Type) -- | Throw an exception. Note that this throws when this action is run in -- the monad m, not when it is applied. It is a generalization -- of Control.Exception's throwIO. -- -- Should satisfy the law: -- --
-- throwM e >> f = throwM e --throwM :: (MonadThrow m, Exception e) => e -> m a -- | See examples in Control.Monad.Reader. Note, the partially -- applied function type (->) r is a simple reader monad. See -- the instance declaration below. class Monad m => MonadReader r (m :: Type -> Type) | m -> r -- | Retrieves the monad environment. ask :: MonadReader r m => m r -- | Executes a computation in a modified environment. local :: MonadReader r m => (r -> r) -> m a -> m a -- | Retrieves a function of the current environment. reader :: MonadReader r m => (r -> a) -> m a -- | The class of monad transformers. Instances should satisfy the -- following laws, which state that lift is a monad -- transformation: -- -- class MonadTrans (t :: Type -> Type -> Type -> Type) -- | Lift a computation from the argument monad to the constructed monad. lift :: (MonadTrans t, Monad m) => m a -> t m a -- | In many situations, the liftM operations can be replaced by -- uses of ap, which promotes function application. -- --
-- return f `ap` x1 `ap` ... `ap` xn ---- -- is equivalent to -- --
-- liftMn f x1 x2 ... xn --ap :: Monad m => m (a -> b) -> m a -> m b -- | Template Haskell macros to create custom newtype wrappers for the -- Stream type. See the examples below to create the standard -- stream types that were available in streamly versions before 0.9.0. -- -- To use this module, the following extensions must be enabled: -- --
-- >>> :set -XStandaloneDeriving -- -- >>> :set -XTemplateHaskell -- -- >>> :set -XTypeFamilies -- -- >>> :set -XUndecidableInstances ---- -- Import this module unqualified to bring everything needed in scope -- without having to import several other modules. Also, -- Streamly.Data.Stream or Streamly.Data.Stream.Prelude -- must be imported as Stream. -- --
-- >>> import Streamly.Data.Stream.MkType -- -- >>> import qualified Streamly.Data.Stream.Prelude as Stream ---- -- For AsyncT monad type with a concurrent cross product bind: -- --
-- >>> :{ -- bind = flip (Stream.parConcatMap id) -- $(mkCrossType "AsyncT" "bind" True) -- :} ---- -- For WAsyncT monad type with a concurrent interleaved bind: -- --
-- >>> :{ -- bind = flip (Stream.parConcatMap (Stream.interleaved True)) -- $(mkCrossType "WAsyncT" "bind" True) -- :} ---- -- For AheadT monad type with a concurrent ordered cross product -- bind: -- --
-- >>> :{ -- bind = flip (Stream.parConcatMap (Stream.ordered True)) -- $(mkCrossType "AheadT" "bind" True) -- :} ---- -- For ParallelT monad type with an eager concurrent cross product -- bind: -- --
-- >>> :{ -- parBind = flip (Stream.parConcatMap (Stream.eager True)) -- $(mkCrossType "ParallelT" "parBind" True) -- :} ---- -- For ZipSerialM serial zipping applicative type: -- --
-- >>> :{ -- zipApply = Stream.zipWith ($) -- $(mkZipType "ZipSerialM" "zipApply" False) -- :} ---- -- For ZipAsync concurrent zipping applicative type: -- --
-- >>> :{ -- parApply = Stream.parApply id -- $(mkZipType "ZipAsync" "parApply" True) -- :} ---- -- Instead of using these macros directly you could use the generated -- code as well. Use these macros in ghci to generate the required code -- and paste it in your package, you can customize the code as desired. -- See the docs of the macros below for examples about how to view the -- generated code. For example: -- --
-- >>> bind = flip (Stream.parConcatMap id) -- -- >>> expr <- runQ (mkCrossType "AsyncT" "bind" True) ---- --
-- > putStrLn $ pprint expr --module Streamly.Data.Stream.MkType -- | Create a type with a zip-like applicative. -- --
-- >>> expr <- runQ (mkZipType "ZipStream" "zipApply" False) -- -- >>> putStrLn $ pprint expr -- newtype ZipStream m a -- = ZipStream (Stream.Stream m a) -- deriving Foldable -- mkZipStream :: Stream.Stream m a -> ZipStream m a -- mkZipStream = ZipStream -- unZipStream :: ZipStream m a -> Stream.Stream m a -- unZipStream (ZipStream strm) = strm -- deriving instance IsList (ZipStream Identity a) -- deriving instance a ~ -- GHC.Types.Char => IsString (ZipStream Identity a) -- deriving instance GHC.Classes.Eq a => Eq (ZipStream Identity a) -- deriving instance GHC.Classes.Ord a => Ord (ZipStream Identity a) -- instance Show a => Show (ZipStream Identity a) -- where {{-# INLINE show #-}; show (ZipStream strm) = show strm} -- instance Read a => Read (ZipStream Identity a) -- where {{-# INLINE readPrec #-}; readPrec = fmap ZipStream readPrec} -- instance Monad m => Functor (ZipStream m) -- where {{-# INLINE fmap #-}; -- fmap f (ZipStream strm) = ZipStream (fmap f strm)} -- instance Monad m => Applicative (ZipStream m) -- where {{-# INLINE pure #-}; -- pure = ZipStream . Stream.repeat; -- {-# INLINE (<*>) #-}; -- (<*>) (ZipStream strm1) (ZipStream strm2) = ZipStream (zipApply strm1 strm2)} --mkZipType :: String -> String -> Bool -> Q [Dec] -- | Create a type with specific stream combination properties. -- --
-- >>> expr <- runQ (mkCrossType "Parallel" "parBind" True) -- -- >>> putStrLn $ pprint expr -- newtype Parallel m a = Parallel (Stream.Stream m a) -- mkParallel :: Stream.Stream m a -> Parallel m a -- mkParallel = Parallel -- unParallel :: Parallel m a -> Stream.Stream m a -- unParallel (Parallel strm) = strm -- instance Monad m => Functor (Parallel m) -- where {{-# INLINE fmap #-}; -- fmap f (Parallel strm) = Parallel (fmap f strm)} -- instance Stream.MonadAsync m => Monad (Parallel m) -- where {{-# INLINE (>>=) #-}; -- (>>=) (Parallel strm1) f = let f1 a = unParallel (f a) -- in Parallel (parBind strm1 f1)} -- instance Stream.MonadAsync m => Applicative (Parallel m) -- where {{-# INLINE pure #-}; -- pure = Parallel . Stream.fromPure; -- {-# INLINE (<*>) #-}; -- (<*>) = ap} -- instance (Monad (Parallel m), MonadIO m) => MonadIO (Parallel m) -- where {{-# INLINE liftIO #-}; -- liftIO = Parallel . (Stream.fromEffect . liftIO)} -- instance (Monad (Parallel m), -- MonadThrow m) => MonadThrow (Parallel m) -- where {{-# INLINE throwM #-}; -- throwM = Parallel . (Stream.fromEffect . throwM)} --mkCrossType :: String -> String -> Bool -> Q [Dec] -- | Parsing of Strings, producing values. -- -- Derived instances of Read make the following assumptions, which -- derived instances of Show obey: -- --
-- infixr 5 :^: -- data Tree a = Leaf a | Tree a :^: Tree a ---- -- the derived instance of Read in Haskell 2010 is equivalent to -- --
-- instance (Read a) => Read (Tree a) where -- -- readsPrec d r = readParen (d > app_prec) -- (\r -> [(Leaf m,t) | -- ("Leaf",s) <- lex r, -- (m,t) <- readsPrec (app_prec+1) s]) r -- -- ++ readParen (d > up_prec) -- (\r -> [(u:^:v,w) | -- (u,s) <- readsPrec (up_prec+1) r, -- (":^:",t) <- lex s, -- (v,w) <- readsPrec (up_prec+1) t]) r -- -- where app_prec = 10 -- up_prec = 5 ---- -- Note that right-associativity of :^: is unused. -- -- The derived instance in GHC is equivalent to -- --
-- instance (Read a) => Read (Tree a) where -- -- readPrec = parens $ (prec app_prec $ do -- Ident "Leaf" <- lexP -- m <- step readPrec -- return (Leaf m)) -- -- +++ (prec up_prec $ do -- u <- step readPrec -- Symbol ":^:" <- lexP -- v <- step readPrec -- return (u :^: v)) -- -- where app_prec = 10 -- up_prec = 5 -- -- readListPrec = readListPrecDefault ---- -- Why do both readsPrec and readPrec exist, and why does -- GHC opt to implement readPrec in derived Read instances -- instead of readsPrec? The reason is that readsPrec is -- based on the ReadS type, and although ReadS is mentioned -- in the Haskell 2010 Report, it is not a very efficient parser data -- structure. -- -- readPrec, on the other hand, is based on a much more efficient -- ReadPrec datatype (a.k.a "new-style parsers"), but its -- definition relies on the use of the RankNTypes language -- extension. Therefore, readPrec (and its cousin, -- readListPrec) are marked as GHC-only. Nevertheless, it is -- recommended to use readPrec instead of readsPrec -- whenever possible for the efficiency improvements it brings. -- -- As mentioned above, derived Read instances in GHC will -- implement readPrec instead of readsPrec. The default -- implementations of readsPrec (and its cousin, readList) -- will simply use readPrec under the hood. If you are writing a -- Read instance by hand, it is recommended to write it like so: -- --
-- instance Read T where -- readPrec = ... -- readListPrec = readListPrecDefault --class Read a -- | attempts to parse a value from the front of the string, returning a -- list of (parsed value, remaining string) pairs. If there is no -- successful parse, the returned list is empty. -- -- Derived instances of Read and Show satisfy the -- following: -- -- -- -- That is, readsPrec parses the string produced by -- showsPrec, and delivers the value that showsPrec started -- with. readsPrec :: Read a => Int -> ReadS a -- | The method readList is provided to allow the programmer to give -- a specialised way of parsing lists of values. For example, this is -- used by the predefined Read instance of the Char type, -- where values of type String should be are expected to use -- double quotes, rather than square brackets. readList :: Read a => ReadS [a] -- | Proposed replacement for readsPrec using new-style parsers (GHC -- only). readPrec :: Read a => ReadPrec a -- | Proposed replacement for readList using new-style parsers (GHC -- only). The default definition uses readList. Instances that -- define readPrec should also define readListPrec as -- readListPrecDefault. readListPrec :: Read a => ReadPrec [a] -- | Monads in which IO computations may be embedded. Any monad -- built by applying a sequence of monad transformers to the IO -- monad will be an instance of this class. -- -- Instances should satisfy the following laws, which state that -- liftIO is a transformer of monads: -- -- class Monad m => MonadIO (m :: Type -> Type) -- | Lift a computation from the IO monad. This allows us to run IO -- computations in any monadic stack, so long as it supports these kinds -- of operations (i.e. IO is the base monad for the stack). -- --
-- import Control.Monad.Trans.State -- from the "transformers" library -- -- printState :: Show s => StateT s IO () -- printState = do -- state <- get -- liftIO $ print state ---- -- Had we omitted liftIO, we would have ended up with -- this error: -- --
-- • Couldn't match type ‘IO’ with ‘StateT s IO’ -- Expected type: StateT s IO () -- Actual type: IO () ---- -- The important part here is the mismatch between StateT s IO -- () and IO (). -- -- Luckily, we know of a function that takes an IO a and -- returns an (m a): liftIO, enabling us to run -- the program and see the expected results: -- --
-- > evalStateT printState "hello" -- "hello" -- -- > evalStateT printState 3 -- 3 --liftIO :: MonadIO m => IO a -> m a -- | A class for monads in which exceptions may be thrown. -- -- Instances should obey the following law: -- --
-- throwM e >> x = throwM e ---- -- In other words, throwing an exception short-circuits the rest of the -- monadic computation. class Monad m => MonadThrow (m :: Type -> Type) -- | Throw an exception. Note that this throws when this action is run in -- the monad m, not when it is applied. It is a generalization -- of Control.Exception's throwIO. -- -- Should satisfy the law: -- --
-- throwM e >> f = throwM e --throwM :: (MonadThrow m, Exception e) => e -> m a -- | See examples in Control.Monad.Reader. Note, the partially -- applied function type (->) r is a simple reader monad. See -- the instance declaration below. class Monad m => MonadReader r (m :: Type -> Type) | m -> r -- | Retrieves the monad environment. ask :: MonadReader r m => m r -- | Executes a computation in a modified environment. local :: MonadReader r m => (r -> r) -> m a -> m a -- | Retrieves a function of the current environment. reader :: MonadReader r m => (r -> a) -> m a -- | The class of monad transformers. Instances should satisfy the -- following laws, which state that lift is a monad -- transformation: -- -- class MonadTrans (t :: Type -> Type -> Type -> Type) -- | Lift a computation from the argument monad to the constructed monad. lift :: (MonadTrans t, Monad m) => m a -> t m a -- | Identity functor and monad. (a non-strict monad) data Identity a -- | The IsList class and its methods are intended to be used in -- conjunction with the OverloadedLists extension. class IsList l -- | Class for string-like datastructures; used by the overloaded string -- extension (-XOverloadedStrings in GHC). class IsString a -- | In many situations, the liftM operations can be replaced by -- uses of ap, which promotes function application. -- --
-- return f `ap` x1 `ap` ... `ap` xn ---- -- is equivalent to -- --
-- liftMn f x1 x2 ... xn --ap :: Monad m => m (a -> b) -> m a -> m b -- | To run examples in this module: -- --
-- >>> import qualified Streamly.Prelude as Stream ---- | Deprecated: Please use Streamly.Internal.Data.Stream from -- streamly-core package instead. module Streamly.Internal.Data.Stream.Serial -- | For SerialT streams: -- --
-- (<>) = serial -- Semigroup -- (>>=) = flip . concatMapWith serial -- Monad ---- -- A single Monad bind behaves like a for loop: -- --
-- >>> :{ -- IsStream.toList $ do -- x <- IsStream.fromList [1,2] -- foreach x in stream -- return x -- :} -- [1,2] ---- -- Nested monad binds behave like nested for loops: -- --
-- >>> :{ -- IsStream.toList $ do -- x <- IsStream.fromList [1,2] -- foreach x in stream -- y <- IsStream.fromList [3,4] -- foreach y in stream -- return (x, y) -- :} -- [(1,3),(1,4),(2,3),(2,4)] ---- -- Since: 0.2.0 (Streamly) newtype SerialT m a SerialT :: Stream m a -> SerialT m a [getSerialT] :: SerialT m a -> Stream m a toStreamK :: SerialT m a -> Stream m a fromStreamK :: Stream m a -> SerialT m a -- | A serial IO stream of elements of type a. See SerialT -- documentation for more details. -- -- Since: 0.2.0 (Streamly) type Serial = SerialT IO serial :: SerialT m a -> SerialT m a -> SerialT m a -- | For WSerialT streams: -- --
-- (<>) = wSerial -- Semigroup -- (>>=) = flip . concatMapWith wSerial -- Monad ---- -- Note that <> is associative only if we disregard the -- ordering of elements in the resulting stream. -- -- A single Monad bind behaves like a for loop: -- --
-- >>> :{ -- IsStream.toList $ IsStream.fromWSerial $ do -- x <- IsStream.fromList [1,2] -- foreach x in stream -- return x -- :} -- [1,2] ---- -- Nested monad binds behave like interleaved nested for loops: -- --
-- >>> :{ -- IsStream.toList $ IsStream.fromWSerial $ do -- x <- IsStream.fromList [1,2] -- foreach x in stream -- y <- IsStream.fromList [3,4] -- foreach y in stream -- return (x, y) -- :} -- [(1,3),(2,3),(1,4),(2,4)] ---- -- It is a result of interleaving all the nested iterations corresponding -- to element 1 in the first stream with all the nested -- iterations of element 2: -- --
-- >>> import Streamly.Prelude (wSerial) -- -- >>> IsStream.toList $ IsStream.fromList [(1,3),(1,4)] `IsStream.wSerial` IsStream.fromList [(2,3),(2,4)] -- [(1,3),(2,3),(1,4),(2,4)] ---- -- The W in the name stands for wide or breadth wise -- scheduling in contrast to the depth wise scheduling behavior of -- SerialT. -- -- Since: 0.2.0 (Streamly) newtype WSerialT m a WSerialT :: Stream m a -> WSerialT m a [getWSerialT] :: WSerialT m a -> Stream m a -- | An interleaving serial IO stream of elements of type a. See -- WSerialT documentation for more details. -- -- Since: 0.2.0 (Streamly) type WSerial = WSerialT IO -- | Interleaves two streams, yielding one element from each stream -- alternately. When one stream stops the rest of the other stream is -- used in the output stream. -- -- This gives exponential priority to earlier streams than the ones -- joining later. Because of exponential weighting it can be used with -- concatMapWith. -- -- Not fused wSerial :: WSerialT m a -> WSerialT m a -> WSerialT m a infixr 6 `wSerial` wSerialFst :: WSerialT m a -> WSerialT m a -> WSerialT m a wSerialMin :: WSerialT m a -> WSerialT m a -> WSerialT m a consMWSerial :: Monad m => m a -> WSerialT m a -> WSerialT m a cons :: a -> SerialT m a -> SerialT m a infixr 5 `cons` consM :: Monad m => m a -> SerialT m a -> SerialT m a infixr 5 `consM` -- | Generate an infinite stream by repeating a pure value. repeat :: Monad m => a -> SerialT m a -- | Build a stream by unfolding a monadic step function starting -- from a seed. The step function returns the next element in the stream -- and the next seed value. When it is done it returns Nothing and -- the stream ends. For example, -- --
-- let f b = -- if b > 3 -- then return Nothing -- else print b >> return (Just (b, b + 1)) -- in drain $ unfoldrM f 0 ---- --
-- 0 -- 1 -- 2 -- 3 ---- -- Pre-release unfoldrM :: Monad m => (b -> m (Maybe (a, b))) -> b -> SerialT m a -- | The fromList function constructs the structure l from -- the given list of Item l fromList :: IsList l => [Item l] -> l -- | The toList function extracts a list of Item l from the -- structure l. It should satisfy fromList . toList = id. toList :: IsList l => l -> [Item l] -- |
-- map = fmap ---- -- Same as fmap. -- --
-- > S.toList $ S.map (+1) $ S.fromList [1,2,3] -- [2,3,4] --map :: Monad m => (a -> b) -> SerialT m a -> SerialT m b mapM :: Monad m => (a -> m b) -> SerialT m a -> SerialT m b instance GHC.Base.Monoid (Streamly.Internal.Data.Stream.Serial.SerialT m a) instance GHC.Base.Semigroup (Streamly.Internal.Data.Stream.Serial.SerialT m a) instance Control.Monad.Trans.Class.MonadTrans Streamly.Internal.Data.Stream.Serial.WSerialT instance GHC.Base.Semigroup (Streamly.Internal.Data.Stream.Serial.WSerialT m a) instance GHC.Base.Monoid (Streamly.Internal.Data.Stream.Serial.WSerialT m a) instance GHC.Base.Monad m => GHC.Base.Applicative (Streamly.Internal.Data.Stream.Serial.WSerialT m) instance GHC.Base.Monad m => GHC.Base.Monad (Streamly.Internal.Data.Stream.Serial.WSerialT m) instance GHC.Base.Monad m => GHC.Base.Functor (Streamly.Internal.Data.Stream.Serial.WSerialT m) instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (Streamly.Internal.Data.Stream.Serial.WSerialT m) instance Control.Monad.Catch.MonadThrow m => Control.Monad.Catch.MonadThrow (Streamly.Internal.Data.Stream.Serial.WSerialT m) instance Control.Monad.Reader.Class.MonadReader r m => Control.Monad.Reader.Class.MonadReader r (Streamly.Internal.Data.Stream.Serial.WSerialT m) instance Control.Monad.State.Class.MonadState s m => Control.Monad.State.Class.MonadState s (Streamly.Internal.Data.Stream.Serial.WSerialT m) instance GHC.Exts.IsList (Streamly.Internal.Data.Stream.Serial.WSerialT Data.Functor.Identity.Identity a) instance GHC.Classes.Eq a => GHC.Classes.Eq (Streamly.Internal.Data.Stream.Serial.WSerialT Data.Functor.Identity.Identity a) instance GHC.Classes.Ord a => GHC.Classes.Ord (Streamly.Internal.Data.Stream.Serial.WSerialT Data.Functor.Identity.Identity a) instance GHC.Show.Show a => GHC.Show.Show (Streamly.Internal.Data.Stream.Serial.WSerialT Data.Functor.Identity.Identity a) instance GHC.Read.Read a => GHC.Read.Read (Streamly.Internal.Data.Stream.Serial.WSerialT Data.Functor.Identity.Identity a) instance (a GHC.Types.~ GHC.Types.Char) => Data.String.IsString (Streamly.Internal.Data.Stream.Serial.WSerialT Data.Functor.Identity.Identity a) instance Control.DeepSeq.NFData a => Control.DeepSeq.NFData (Streamly.Internal.Data.Stream.Serial.WSerialT Data.Functor.Identity.Identity a) instance Control.DeepSeq.NFData1 (Streamly.Internal.Data.Stream.Serial.WSerialT Data.Functor.Identity.Identity) instance (Data.Foldable.Foldable m, GHC.Base.Monad m) => Data.Foldable.Foldable (Streamly.Internal.Data.Stream.Serial.WSerialT m) instance Data.Traversable.Traversable (Streamly.Internal.Data.Stream.Serial.WSerialT Data.Functor.Identity.Identity) instance GHC.Base.Monad m => GHC.Base.Monad (Streamly.Internal.Data.Stream.Serial.SerialT m) instance Control.Monad.Trans.Class.MonadTrans Streamly.Internal.Data.Stream.Serial.SerialT instance GHC.Base.Monad m => GHC.Base.Applicative (Streamly.Internal.Data.Stream.Serial.SerialT m) instance GHC.Base.Monad m => GHC.Base.Functor (Streamly.Internal.Data.Stream.Serial.SerialT m) instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (Streamly.Internal.Data.Stream.Serial.SerialT m) instance Control.Monad.Catch.MonadThrow m => Control.Monad.Catch.MonadThrow (Streamly.Internal.Data.Stream.Serial.SerialT m) instance Control.Monad.Reader.Class.MonadReader r m => Control.Monad.Reader.Class.MonadReader r (Streamly.Internal.Data.Stream.Serial.SerialT m) instance Control.Monad.State.Class.MonadState s m => Control.Monad.State.Class.MonadState s (Streamly.Internal.Data.Stream.Serial.SerialT m) instance GHC.Exts.IsList (Streamly.Internal.Data.Stream.Serial.SerialT Data.Functor.Identity.Identity a) instance GHC.Classes.Eq a => GHC.Classes.Eq (Streamly.Internal.Data.Stream.Serial.SerialT Data.Functor.Identity.Identity a) instance GHC.Classes.Ord a => GHC.Classes.Ord (Streamly.Internal.Data.Stream.Serial.SerialT Data.Functor.Identity.Identity a) instance GHC.Show.Show a => GHC.Show.Show (Streamly.Internal.Data.Stream.Serial.SerialT Data.Functor.Identity.Identity a) instance GHC.Read.Read a => GHC.Read.Read (Streamly.Internal.Data.Stream.Serial.SerialT Data.Functor.Identity.Identity a) instance (a GHC.Types.~ GHC.Types.Char) => Data.String.IsString (Streamly.Internal.Data.Stream.Serial.SerialT Data.Functor.Identity.Identity a) instance Control.DeepSeq.NFData a => Control.DeepSeq.NFData (Streamly.Internal.Data.Stream.Serial.SerialT Data.Functor.Identity.Identity a) instance Control.DeepSeq.NFData1 (Streamly.Internal.Data.Stream.Serial.SerialT Data.Functor.Identity.Identity) instance (Data.Foldable.Foldable m, GHC.Base.Monad m) => Data.Foldable.Foldable (Streamly.Internal.Data.Stream.Serial.SerialT m) instance Data.Traversable.Traversable (Streamly.Internal.Data.Stream.Serial.SerialT Data.Functor.Identity.Identity) instance (Control.Monad.Base.MonadBase b m, GHC.Base.Monad m) => Control.Monad.Base.MonadBase b (Streamly.Internal.Data.Stream.Serial.SerialT m) -- | Deprecated: This module will be removed in future. module Streamly.Internal.Data.Stream.SVar -- | Fold the supplied stream to the SVar asynchronously using Parallel -- concurrency style. {-# INLINE [1] toSVarParallel #-} toSVarParallel :: MonadAsync m => State t m a -> SVar t m a -> Stream m a -> m () -- | Create a Fold style SVar that runs a supplied fold function as the -- consumer. Any elements sent to the SVar are consumed by the supplied -- fold function. newFoldSVar :: MonadAsync m => State Stream m a -> (SerialT m a -> m b) -> m (SVar Stream m a) -- | Like newFoldSVar except that it uses a Fold instead of a -- fold function. newFoldSVarF :: MonadAsync m => State t m a -> Fold m a b -> m (SVar t m a) -- | Poll for events sent by the fold consumer to the stream pusher. The -- fold consumer can send a Stop event or an exception. When a -- Stop is received this function returns True. If an -- exception is recieved then it throws the exception. fromConsumer :: MonadAsync m => SVar Stream m a -> m Bool -- | Push values from a stream to a fold worker via an SVar. Before pushing -- a value to the SVar it polls for events received from the fold -- consumer. If a stop event is received then it returns True -- otherwise false. Propagates exceptions received from the fold -- consumer. pushToFold :: MonadAsync m => SVar Stream m a -> a -> m Bool -- | Tap a stream and send the elements to the specified SVar in addition -- to yielding them again. The SVar runs a fold consumer. Elements are -- tapped and sent to the SVar until the fold finishes. Any exceptions -- from the fold evaluation are propagated in the current thread. -- --
-- ------input stream---------output stream-----> -- /|\ | -- exceptions | | input -- | \|/ -- ----SVar -- | -- Fold --teeToSVar :: MonadAsync m => SVar Stream m a -> SerialT m a -> SerialT m a -- | Write a stream to an SVar in a non-blocking manner. The stream -- can then be read back from the SVar using fromSVar. toSVar :: MonadAsync m => SVar SerialT m a -> SerialT m a -> m () -- | Generate a stream from an SVar. An unevaluated stream can be pushed to -- an SVar using toSVar. As we pull a stream from the SVar the -- input stream gets evaluated concurrently. The evaluation depends on -- the SVar style and the configuration parameters e.g. using the -- maxBuffer/maxThreads combinators. fromSVar :: MonadAsync m => SVar Stream m a -> SerialT m a -- | Like fromSVar but generates a StreamD style stream instead of -- CPS. fromSVarD :: MonadAsync m => SVar t m a -> Stream m a -- | To run examples in this module: -- --
-- >>> import qualified Streamly.Prelude as Stream -- -- >>> import Control.Concurrent (threadDelay) -- -- >>> :{ -- delay n = do -- threadDelay (n * 1000000) -- sleep for n seconds -- putStrLn (show n ++ " sec") -- print "n sec" -- return n -- IO Int -- :} ---- | Deprecated: Please use -- Streamly.Internal.Data.Stream.Concurrent instead. module Streamly.Internal.Data.Stream.Parallel -- | For ParallelT streams: -- --
-- (<>) = parallel -- (>>=) = flip . concatMapWith parallel ---- -- See AsyncT, ParallelT is similar except that all -- iterations are strictly concurrent while in AsyncT it depends -- on the consumer demand and available threads. See parallel -- for more details. -- -- Since: 0.1.0 (Streamly) -- -- Since: 0.7.0 (maxBuffer applies to ParallelT streams) newtype ParallelT m a ParallelT :: StreamK m a -> ParallelT m a [getParallelT] :: ParallelT m a -> StreamK m a -- | A parallely composing IO stream of elements of type a. See -- ParallelT documentation for more details. -- -- Since: 0.2.0 (Streamly) type Parallel = ParallelT IO -- | XXX we can implement it more efficienty by directly implementing -- instead of combining streams using parallel. consM :: MonadAsync m => m a -> ParallelT m a -> ParallelT m a parallelK :: MonadAsync m => StreamK m a -> StreamK m a -> StreamK m a -- | Like parallel but stops the output as soon as the first -- stream stops. -- -- Pre-release parallelFstK :: MonadAsync m => StreamK m a -> StreamK m a -> StreamK m a -- | Like parallel but stops the output as soon as any of the two -- streams stops. -- -- Pre-release parallelMinK :: MonadAsync m => StreamK m a -> StreamK m a -> StreamK m a -- | Same as mkParallel but for StreamD stream. mkParallelD :: MonadAsync m => Stream m a -> Stream m a -- | Like mkParallel but uses StreamK internally. -- -- Pre-release mkParallelK :: MonadAsync m => StreamK m a -> StreamK m a -- | Redirect a copy of the stream to a supplied fold and run it -- concurrently in an independent thread. The fold may buffer some -- elements. The buffer size is determined by the prevailing -- maxBuffer setting. -- --
-- StreamK m a -> m b -- | -- -----stream m a ---------------stream m a----- ---- --
-- > S.drain $ S.tapAsync (S.mapM_ print) (S.enumerateFromTo 1 2) -- 1 -- 2 ---- -- Exceptions from the concurrently running fold are propagated to the -- current computation. Note that, because of buffering in the fold, -- exceptions may be delayed and may not correspond to the current -- element being processed in the parent stream, but we guarantee that -- before the parent stream stops the tap finishes and all exceptions -- from it are drained. -- -- Compare with tap. -- -- Pre-release tapAsyncK :: MonadAsync m => (StreamK m a -> m b) -> StreamK m a -> StreamK m a -- | Like tapAsync but uses a Fold instead of a fold -- function. tapAsyncF :: MonadAsync m => Fold m a b -> Stream m a -> Stream m a -- | Generates a callback and a stream pair. The callback returned is used -- to queue values to the stream. The stream is infinite, there is no way -- for the callback to indicate that it is done now. -- -- Pre-release newCallbackStream :: MonadAsync m => m (a -> m (), StreamK m a) instance Control.Monad.Trans.Class.MonadTrans Streamly.Internal.Data.Stream.Parallel.ParallelT instance Streamly.Internal.Control.Concurrent.MonadAsync m => GHC.Base.Semigroup (Streamly.Internal.Data.Stream.Parallel.ParallelT m a) instance Streamly.Internal.Control.Concurrent.MonadAsync m => GHC.Base.Monoid (Streamly.Internal.Data.Stream.Parallel.ParallelT m a) instance (GHC.Base.Monad m, Streamly.Internal.Control.Concurrent.MonadAsync m) => GHC.Base.Applicative (Streamly.Internal.Data.Stream.Parallel.ParallelT m) instance Streamly.Internal.Control.Concurrent.MonadAsync m => GHC.Base.Monad (Streamly.Internal.Data.Stream.Parallel.ParallelT m) instance (Control.Monad.Base.MonadBase b m, GHC.Base.Monad m, Streamly.Internal.Control.Concurrent.MonadAsync m) => Control.Monad.Base.MonadBase b (Streamly.Internal.Data.Stream.Parallel.ParallelT m) instance GHC.Base.Monad m => GHC.Base.Functor (Streamly.Internal.Data.Stream.Parallel.ParallelT m) instance (Control.Monad.IO.Class.MonadIO m, Streamly.Internal.Control.Concurrent.MonadAsync m) => Control.Monad.IO.Class.MonadIO (Streamly.Internal.Data.Stream.Parallel.ParallelT m) instance (Control.Monad.Catch.MonadThrow m, Streamly.Internal.Control.Concurrent.MonadAsync m) => Control.Monad.Catch.MonadThrow (Streamly.Internal.Data.Stream.Parallel.ParallelT m) instance (Control.Monad.Reader.Class.MonadReader r m, Streamly.Internal.Control.Concurrent.MonadAsync m) => Control.Monad.Reader.Class.MonadReader r (Streamly.Internal.Data.Stream.Parallel.ParallelT m) instance (Control.Monad.State.Class.MonadState s m, Streamly.Internal.Control.Concurrent.MonadAsync m) => Control.Monad.State.Class.MonadState s (Streamly.Internal.Data.Stream.Parallel.ParallelT m) -- | To run examples in this module: -- --
-- >>> import qualified Streamly.Prelude as Stream -- -- >>> import Control.Concurrent (threadDelay) -- -- >>> :{ -- delay n = do -- threadDelay (n * 1000000) -- sleep for n seconds -- putStrLn (show n ++ " sec") -- print "n sec" -- return n -- IO Int -- :} ---- | Deprecated: Please use -- Streamly.Internal.Data.Stream.Concurrent from streamly package -- instead. module Streamly.Internal.Data.Stream.Async -- | For AsyncT streams: -- --
-- (<>) = async -- (>>=) = flip . concatMapWith async ---- -- A single Monad bind behaves like a for loop with -- iterations of the loop executed concurrently a la the async -- combinator, producing results and side effects of iterations out of -- order: -- --
-- >>> :{ -- Stream.toList $ Stream.fromAsync $ do -- x <- Stream.fromList [2,1] -- foreach x in stream -- Stream.fromEffect $ delay x -- :} -- 1 sec -- 2 sec -- [1,2] ---- -- Nested monad binds behave like nested for loops with nested -- iterations executed concurrently, a la the async combinator: -- --
-- >>> :{ -- Stream.toList $ Stream.fromAsync $ do -- x <- Stream.fromList [1,2] -- foreach x in stream -- y <- Stream.fromList [2,4] -- foreach y in stream -- Stream.fromEffect $ delay (x + y) -- :} -- 3 sec -- 4 sec -- 5 sec -- 6 sec -- [3,4,5,6] ---- -- The behavior can be explained as follows. All the iterations -- corresponding to the element 1 in the first stream constitute -- one output stream and all the iterations corresponding to 2 -- constitute another output stream and these two output streams are -- merged using async. -- -- Since: 0.1.0 (Streamly) newtype AsyncT m a AsyncT :: Stream m a -> AsyncT m a [getAsyncT] :: AsyncT m a -> Stream m a -- | A demand driven left biased parallely composing IO stream of elements -- of type a. See AsyncT documentation for more details. -- -- Since: 0.2.0 (Streamly) type Async = AsyncT IO -- | XXX we can implement it more efficienty by directly implementing -- instead of combining streams using async. consMAsync :: MonadAsync m => m a -> AsyncT m a -> AsyncT m a asyncK :: MonadAsync m => Stream m a -> Stream m a -> Stream m a -- | Generate a stream asynchronously to keep it buffered, lazily consume -- from the buffer. -- -- Pre-release mkAsyncK :: MonadAsync m => Stream m a -> Stream m a mkAsyncD :: MonadAsync m => Stream m a -> Stream m a -- | For WAsyncT streams: -- --
-- (<>) = wAsync -- (>>=) = flip . concatMapWith wAsync ---- -- A single Monad bind behaves like a for loop with -- iterations of the loop executed concurrently a la the wAsync -- combinator, producing results and side effects of iterations out of -- order: -- --
-- >>> :{ -- Stream.toList $ Stream.fromWAsync $ do -- x <- Stream.fromList [2,1] -- foreach x in stream -- Stream.fromEffect $ delay x -- :} -- 1 sec -- 2 sec -- [1,2] ---- -- Nested monad binds behave like nested for loops with nested -- iterations executed concurrently, a la the wAsync combinator: -- --
-- >>> :{ -- Stream.toList $ Stream.fromWAsync $ do -- x <- Stream.fromList [1,2] -- foreach x in stream -- y <- Stream.fromList [2,4] -- foreach y in stream -- Stream.fromEffect $ delay (x + y) -- :} -- 3 sec -- 4 sec -- 5 sec -- 6 sec -- [3,4,5,6] ---- -- The behavior can be explained as follows. All the iterations -- corresponding to the element 1 in the first stream constitute -- one WAsyncT output stream and all the iterations corresponding -- to 2 constitute another WAsyncT output stream and -- these two output streams are merged using wAsync. -- -- The W in the name stands for wide or breadth wise -- scheduling in contrast to the depth wise scheduling behavior of -- AsyncT. -- -- Since: 0.2.0 (Streamly) newtype WAsyncT m a WAsyncT :: Stream m a -> WAsyncT m a [getWAsyncT] :: WAsyncT m a -> Stream m a -- | A round robin parallely composing IO stream of elements of type -- a. See WAsyncT documentation for more details. -- -- Since: 0.2.0 (Streamly) type WAsync = WAsyncT IO -- | XXX we can implement it more efficienty by directly implementing -- instead of combining streams using wAsync. consMWAsync :: MonadAsync m => m a -> WAsyncT m a -> WAsyncT m a wAsyncK :: MonadAsync m => Stream m a -> Stream m a -> Stream m a instance Control.Monad.Trans.Class.MonadTrans Streamly.Internal.Data.Stream.Async.WAsyncT instance Streamly.Internal.Control.Concurrent.MonadAsync m => GHC.Base.Semigroup (Streamly.Internal.Data.Stream.Async.WAsyncT m a) instance Streamly.Internal.Control.Concurrent.MonadAsync m => GHC.Base.Monoid (Streamly.Internal.Data.Stream.Async.WAsyncT m a) instance (GHC.Base.Monad m, Streamly.Internal.Control.Concurrent.MonadAsync m) => GHC.Base.Applicative (Streamly.Internal.Data.Stream.Async.WAsyncT m) instance Streamly.Internal.Control.Concurrent.MonadAsync m => GHC.Base.Monad (Streamly.Internal.Data.Stream.Async.WAsyncT m) instance (Control.Monad.Base.MonadBase b m, GHC.Base.Monad m, Streamly.Internal.Control.Concurrent.MonadAsync m) => Control.Monad.Base.MonadBase b (Streamly.Internal.Data.Stream.Async.WAsyncT m) instance GHC.Base.Monad m => GHC.Base.Functor (Streamly.Internal.Data.Stream.Async.WAsyncT m) instance (Control.Monad.IO.Class.MonadIO m, Streamly.Internal.Control.Concurrent.MonadAsync m) => Control.Monad.IO.Class.MonadIO (Streamly.Internal.Data.Stream.Async.WAsyncT m) instance (Control.Monad.Catch.MonadThrow m, Streamly.Internal.Control.Concurrent.MonadAsync m) => Control.Monad.Catch.MonadThrow (Streamly.Internal.Data.Stream.Async.WAsyncT m) instance (Control.Monad.Reader.Class.MonadReader r m, Streamly.Internal.Control.Concurrent.MonadAsync m) => Control.Monad.Reader.Class.MonadReader r (Streamly.Internal.Data.Stream.Async.WAsyncT m) instance (Control.Monad.State.Class.MonadState s m, Streamly.Internal.Control.Concurrent.MonadAsync m) => Control.Monad.State.Class.MonadState s (Streamly.Internal.Data.Stream.Async.WAsyncT m) instance Control.Monad.Trans.Class.MonadTrans Streamly.Internal.Data.Stream.Async.AsyncT instance Streamly.Internal.Control.Concurrent.MonadAsync m => GHC.Base.Semigroup (Streamly.Internal.Data.Stream.Async.AsyncT m a) instance Streamly.Internal.Control.Concurrent.MonadAsync m => GHC.Base.Monoid (Streamly.Internal.Data.Stream.Async.AsyncT m a) instance (GHC.Base.Monad m, Streamly.Internal.Control.Concurrent.MonadAsync m) => GHC.Base.Applicative (Streamly.Internal.Data.Stream.Async.AsyncT m) instance Streamly.Internal.Control.Concurrent.MonadAsync m => GHC.Base.Monad (Streamly.Internal.Data.Stream.Async.AsyncT m) instance (Control.Monad.Base.MonadBase b m, GHC.Base.Monad m, Streamly.Internal.Control.Concurrent.MonadAsync m) => Control.Monad.Base.MonadBase b (Streamly.Internal.Data.Stream.Async.AsyncT m) instance GHC.Base.Monad m => GHC.Base.Functor (Streamly.Internal.Data.Stream.Async.AsyncT m) instance (Control.Monad.IO.Class.MonadIO m, Streamly.Internal.Control.Concurrent.MonadAsync m) => Control.Monad.IO.Class.MonadIO (Streamly.Internal.Data.Stream.Async.AsyncT m) instance (Control.Monad.Catch.MonadThrow m, Streamly.Internal.Control.Concurrent.MonadAsync m) => Control.Monad.Catch.MonadThrow (Streamly.Internal.Data.Stream.Async.AsyncT m) instance (Control.Monad.Reader.Class.MonadReader r m, Streamly.Internal.Control.Concurrent.MonadAsync m) => Control.Monad.Reader.Class.MonadReader r (Streamly.Internal.Data.Stream.Async.AsyncT m) instance (Control.Monad.State.Class.MonadState s m, Streamly.Internal.Control.Concurrent.MonadAsync m) => Control.Monad.State.Class.MonadState s (Streamly.Internal.Data.Stream.Async.AsyncT m) -- | To run examples in this module: -- --
-- >>> import qualified Streamly.Prelude as Stream -- -- >>> import Control.Concurrent (threadDelay) -- -- >>> :{ -- delay n = do -- threadDelay (n * 1000000) -- sleep for n seconds -- putStrLn (show n ++ " sec") -- print "n sec" -- return n -- IO Int -- :} ---- | Deprecated: Please use -- Streamly.Internal.Data.Stream.Concurrent from streamly package -- instead. module Streamly.Internal.Data.Stream.Ahead -- | For AheadT streams: -- --
-- (<>) = ahead -- (>>=) = flip . concatMapWith ahead ---- -- A single Monad bind behaves like a for loop with -- iterations executed concurrently, ahead of time, producing side -- effects of iterations out of order, but results in order: -- --
-- >>> :{ -- Stream.toList $ Stream.fromAhead $ do -- x <- Stream.fromList [2,1] -- foreach x in stream -- Stream.fromEffect $ delay x -- :} -- 1 sec -- 2 sec -- [2,1] ---- -- Nested monad binds behave like nested for loops with nested -- iterations executed concurrently, ahead of time: -- --
-- >>> :{ -- Stream.toList $ Stream.fromAhead $ do -- x <- Stream.fromList [1,2] -- foreach x in stream -- y <- Stream.fromList [2,4] -- foreach y in stream -- Stream.fromEffect $ delay (x + y) -- :} -- 3 sec -- 4 sec -- 5 sec -- 6 sec -- [3,5,4,6] ---- -- The behavior can be explained as follows. All the iterations -- corresponding to the element 1 in the first stream constitute -- one output stream and all the iterations corresponding to 2 -- constitute another output stream and these two output streams are -- merged using ahead. -- -- Since: 0.3.0 (Streamly) newtype AheadT m a AheadT :: Stream m a -> AheadT m a [getAheadT] :: AheadT m a -> Stream m a -- | A serial IO stream of elements of type a with concurrent -- lookahead. See AheadT documentation for more details. -- -- Since: 0.3.0 (Streamly) type Ahead = AheadT IO aheadK :: MonadAsync m => Stream m a -> Stream m a -> Stream m a -- | XXX we can implement it more efficienty by directly implementing -- instead of combining streams using ahead. consM :: MonadAsync m => m a -> AheadT m a -> AheadT m a instance Control.Monad.Trans.Class.MonadTrans Streamly.Internal.Data.Stream.Ahead.AheadT instance Streamly.Internal.Control.Concurrent.MonadAsync m => GHC.Base.Semigroup (Streamly.Internal.Data.Stream.Ahead.AheadT m a) instance Streamly.Internal.Control.Concurrent.MonadAsync m => GHC.Base.Monoid (Streamly.Internal.Data.Stream.Ahead.AheadT m a) instance (GHC.Base.Monad m, Streamly.Internal.Control.Concurrent.MonadAsync m) => GHC.Base.Applicative (Streamly.Internal.Data.Stream.Ahead.AheadT m) instance Streamly.Internal.Control.Concurrent.MonadAsync m => GHC.Base.Monad (Streamly.Internal.Data.Stream.Ahead.AheadT m) instance (Control.Monad.Base.MonadBase b m, GHC.Base.Monad m, Streamly.Internal.Control.Concurrent.MonadAsync m) => Control.Monad.Base.MonadBase b (Streamly.Internal.Data.Stream.Ahead.AheadT m) instance GHC.Base.Monad m => GHC.Base.Functor (Streamly.Internal.Data.Stream.Ahead.AheadT m) instance (Control.Monad.IO.Class.MonadIO m, Streamly.Internal.Control.Concurrent.MonadAsync m) => Control.Monad.IO.Class.MonadIO (Streamly.Internal.Data.Stream.Ahead.AheadT m) instance (Control.Monad.Catch.MonadThrow m, Streamly.Internal.Control.Concurrent.MonadAsync m) => Control.Monad.Catch.MonadThrow (Streamly.Internal.Data.Stream.Ahead.AheadT m) instance (Control.Monad.Reader.Class.MonadReader r m, Streamly.Internal.Control.Concurrent.MonadAsync m) => Control.Monad.Reader.Class.MonadReader r (Streamly.Internal.Data.Stream.Ahead.AheadT m) instance (Control.Monad.State.Class.MonadState s m, Streamly.Internal.Control.Concurrent.MonadAsync m) => Control.Monad.State.Class.MonadState s (Streamly.Internal.Data.Stream.Ahead.AheadT m) module Streamly.Internal.Data.Stream.Prelude -- | A mutable channel to evaluate multiple streams concurrently and -- provide the combined results as output stream. data Channel m a Channel :: RunInIO m -> IORef ([ChildEvent a], Int) -> MVar () -> m [ChildEvent a] -> m Bool -> Limit -> Limit -> Maybe (IORef Count) -> Maybe YieldRateInfo -> (Bool -> (RunInIO m, StreamK m a) -> IO ()) -> m () -> IO Bool -> IO Bool -> IORef Bool -> (Maybe WorkerInfo -> m ()) -> IORef (Set ThreadId) -> IORef Int -> (ThreadId -> m ()) -> MVar () -> Maybe (IORef ()) -> SVarStats -> Bool -> ThreadId -> Channel m a [svarMrun] :: Channel m a -> RunInIO m [outputQueue] :: Channel m a -> IORef ([ChildEvent a], Int) [outputDoorBell] :: Channel m a -> MVar () [readOutputQ] :: Channel m a -> m [ChildEvent a] [postProcess] :: Channel m a -> m Bool [maxWorkerLimit] :: Channel m a -> Limit [maxBufferLimit] :: Channel m a -> Limit [remainingWork] :: Channel m a -> Maybe (IORef Count) [yieldRateInfo] :: Channel m a -> Maybe YieldRateInfo [enqueue] :: Channel m a -> Bool -> (RunInIO m, StreamK m a) -> IO () [eagerDispatch] :: Channel m a -> m () [isWorkDone] :: Channel m a -> IO Bool [isQueueDone] :: Channel m a -> IO Bool [doorBellOnWorkQ] :: Channel m a -> IORef Bool [workLoop] :: Channel m a -> Maybe WorkerInfo -> m () [workerThreads] :: Channel m a -> IORef (Set ThreadId) [workerCount] :: Channel m a -> IORef Int [accountThread] :: Channel m a -> ThreadId -> m () [workerStopMVar] :: Channel m a -> MVar () [svarRef] :: Channel m a -> Maybe (IORef ()) [svarStats] :: Channel m a -> SVarStats [svarInspectMode] :: Channel m a -> Bool [svarCreator] :: Channel m a -> ThreadId yield :: Channel m a -> Maybe WorkerInfo -> a -> IO Bool stop :: Channel m a -> Maybe WorkerInfo -> IO () -- | Stop the channel. Kill all running worker threads. stopChannel :: MonadIO m => Channel m a -> m () dumpSVar :: Channel m a -> IO String -- | Send a stream to a given channel for concurrent evaluation. toChannel :: MonadRunInIO m => Channel m a -> Stream m a -> m () -- | Write a stream to an SVar in a non-blocking manner. The -- stream can then be read back from the SVar using fromSVar. toChannelK :: MonadRunInIO m => Channel m a -> StreamK m a -> m () -- | Generate a stream of results from concurrent evaluations from a -- channel. Evaluation of the channel does not start until this API is -- called. This API must not be called more than once on a channel. It -- kicks off evaluation of the channel by dispatching concurrent workers -- and ensures that as long there is work queued on the channel workers -- are dispatched proportional to the demand by the consumer. fromChannel :: MonadAsync m => Channel m a -> Stream m a fromChannelK :: MonadAsync m => Channel m a -> StreamK m a -- | Create a new async style concurrent stream evaluation channel. The -- monad state used to run the stream actions is taken from the call site -- of newAppendChannel. newAppendChannel :: MonadRunInIO m => (Config -> Config) -> m (Channel m a) -- | Create a new async style concurrent stream evaluation channel. The -- monad state used to run the stream actions is taken from the call site -- of newInterleaveChannel. newInterleaveChannel :: MonadAsync m => (Config -> Config) -> m (Channel m a) pushWorker :: MonadRunInIO m => Count -> Channel m a -> m () dispatchWorker :: MonadRunInIO m => Count -> Channel m a -> m Bool dispatchWorkerPaced :: MonadRunInIO m => Channel m a -> m Bool sendWorkerWait :: MonadIO m => Bool -> (Channel m a -> IO ()) -> (Channel m a -> m Bool) -> Channel m a -> m () -- | Start the evaluation of the channel's work queue by kicking off a -- worker. Note: Work queue must not be empty otherwise the worker will -- exit without doing anything. startChannel :: MonadRunInIO m => Channel m a -> m () sendWorkerDelay :: Channel m a -> IO () sendWorkerDelayPaced :: Channel m a -> IO () readOutputQPaced :: MonadRunInIO m => Channel m a -> m [ChildEvent a] readOutputQBounded :: MonadRunInIO m => Bool -> Channel m a -> m [ChildEvent a] postProcessPaced :: MonadRunInIO m => Channel m a -> m Bool postProcessBounded :: MonadRunInIO m => Channel m a -> m Bool -- | A mutable channel to evaluate multiple streams concurrently and -- provide the combined results as output stream. data Channel m a Channel :: RunInIO m -> IORef ([ChildEvent a], Int) -> MVar () -> m [ChildEvent a] -> m Bool -> Limit -> Limit -> Maybe (IORef Count) -> Maybe YieldRateInfo -> (Bool -> (RunInIO m, StreamK m a) -> IO ()) -> m () -> IO Bool -> IO Bool -> IORef Bool -> (Maybe WorkerInfo -> m ()) -> IORef (Set ThreadId) -> IORef Int -> (ThreadId -> m ()) -> MVar () -> Maybe (IORef ()) -> SVarStats -> Bool -> ThreadId -> Channel m a [svarMrun] :: Channel m a -> RunInIO m [outputQueue] :: Channel m a -> IORef ([ChildEvent a], Int) [outputDoorBell] :: Channel m a -> MVar () [readOutputQ] :: Channel m a -> m [ChildEvent a] [postProcess] :: Channel m a -> m Bool [maxWorkerLimit] :: Channel m a -> Limit [maxBufferLimit] :: Channel m a -> Limit [remainingWork] :: Channel m a -> Maybe (IORef Count) [yieldRateInfo] :: Channel m a -> Maybe YieldRateInfo [enqueue] :: Channel m a -> Bool -> (RunInIO m, StreamK m a) -> IO () [eagerDispatch] :: Channel m a -> m () [isWorkDone] :: Channel m a -> IO Bool [isQueueDone] :: Channel m a -> IO Bool [doorBellOnWorkQ] :: Channel m a -> IORef Bool [workLoop] :: Channel m a -> Maybe WorkerInfo -> m () [workerThreads] :: Channel m a -> IORef (Set ThreadId) [workerCount] :: Channel m a -> IORef Int [accountThread] :: Channel m a -> ThreadId -> m () [workerStopMVar] :: Channel m a -> MVar () [svarRef] :: Channel m a -> Maybe (IORef ()) [svarStats] :: Channel m a -> SVarStats [svarInspectMode] :: Channel m a -> Bool [svarCreator] :: Channel m a -> ThreadId -- | Create a new concurrent stream evaluation channel. The monad state -- used to run the stream actions is captured from the call site of -- newChannel. newChannel :: MonadAsync m => (Config -> Config) -> m (Channel m a) -- | Allocate a channel and evaluate the stream using the channel and the -- supplied evaluator function. The evaluator is run in a worker thread. withChannel :: MonadAsync m => (Config -> Config) -> Stream m a -> (Channel m b -> Stream m a -> Stream m b) -> Stream m b -- | Allocate a channel and evaluate the stream using the channel and the -- supplied evaluator function. The evaluator is run in a worker thread. withChannelK :: MonadAsync m => (Config -> Config) -> StreamK m a -> (Channel m b -> StreamK m a -> StreamK m b) -> StreamK m b -- | An abstract type for specifying the configuration parameters of a -- Channel. Use Config -> Config modifier functions -- to modify the default configuration. See the individual modifier -- documentation for default values. data Config -- | The fields prefixed by an _ are not to be accessed or updated directly -- but via smart accessor APIs. Use get/set routines instead of directly -- accessing the Config fields defaultConfig :: Config -- | Specify the maximum number of threads that can be spawned by the -- channel. A value of 0 resets the thread limit to default, a negative -- value means there is no limit. The default value is 1500. -- -- When the actions in a stream are IO bound, having blocking IO calls, -- this option can be used to control the maximum number of in-flight IO -- requests. When the actions are CPU bound this option can be used to -- control the amount of CPU used by the stream. maxThreads :: Int -> Config -> Config -- | Specify the maximum size of the buffer for storing the results from -- concurrent computations. If the buffer becomes full we stop spawning -- more concurrent tasks until there is space in the buffer. A value of 0 -- resets the buffer size to default, a negative value means there is no -- limit. The default value is 1500. -- -- CAUTION! using an unbounded maxBuffer value (i.e. a negative -- value) coupled with an unbounded maxThreads value is a recipe -- for disaster in presence of infinite streams, or very large streams. -- Especially, it must not be used when pure is used in -- ZipAsyncM streams as pure in applicative zip streams -- generates an infinite stream causing unbounded concurrent generation -- with no limit on the buffer or threads. maxBuffer :: Int -> Config -> Config -- | Specifies the stream yield rate in yields per second (Hertz). -- We keep accumulating yield credits at rateGoal. At any point of -- time we allow only as many yields as we have accumulated as per -- rateGoal since the start of time. If the consumer or the -- producer is slower or faster, the actual rate may fall behind or -- exceed rateGoal. We try to recover the gap between the two by -- increasing or decreasing the pull rate from the producer. However, if -- the gap becomes more than rateBuffer we try to recover only as -- much as rateBuffer. -- -- rateLow puts a bound on how low the instantaneous rate can go -- when recovering the rate gap. In other words, it determines the -- maximum yield latency. Similarly, rateHigh puts a bound on how -- high the instantaneous rate can go when recovering the rate gap. In -- other words, it determines the minimum yield latency. We reduce the -- latency by increasing concurrency, therefore we can say that it puts -- an upper bound on concurrency. -- -- If the rateGoal is 0 or negative the stream never yields a -- value. If the rateBuffer is 0 or negative we do not attempt to -- recover. data Rate Rate :: Double -> Double -> Double -> Int -> Rate -- | The lower rate limit [rateLow] :: Rate -> Double -- | The target rate we want to achieve [rateGoal] :: Rate -> Double -- | The upper rate limit [rateHigh] :: Rate -> Double -- | Maximum slack from the goal [rateBuffer] :: Rate -> Int -- | Specify the stream evaluation rate of a channel. -- -- A Nothing value means there is no smart rate control, -- concurrent execution blocks only if maxThreads or -- maxBuffer is reached, or there are no more concurrent tasks to -- execute. This is the default. -- -- When rate (throughput) is specified, concurrent production may be -- ramped up or down automatically to achieve the specified stream -- throughput. The specific behavior for different styles of Rate -- specifications is documented under Rate. The effective maximum -- production rate achieved by a channel is governed by: -- --
-- >>> parUnfoldrM step = Stream.parEval id . Stream.unfoldrM step -- -- >>> parIterateM step = Stream.parEval id . Stream.iterateM step --parEval :: MonadAsync m => (Config -> Config) -> Stream m a -> Stream m a -- | Definition: -- --
-- >>> parRepeatM cfg = Stream.parSequence cfg . Stream.repeat ---- -- Generate a stream by repeatedly executing a monadic action forever. parRepeatM :: MonadAsync m => (Config -> Config) -> m a -> Stream m a -- | Generate a stream by concurrently performing a monadic action -- n times. -- -- Definition: -- --
-- >>> parReplicateM cfg n = Stream.parSequence cfg . Stream.replicate n ---- -- Example, parReplicateM in the following example executes all -- the replicated actions concurrently, thus taking only 1 second: -- --
-- >>> Stream.fold Fold.drain $ Stream.parReplicateM id 10 $ delay 1 -- ... --parReplicateM :: MonadAsync m => (Config -> Config) -> Int -> m a -> Stream m a -- | Definition: -- --
-- >>> parMapM modifier f = Stream.parConcatMap modifier (Stream.fromEffect . f) ---- -- For example, the following finishes in 3 seconds (as opposed to 6 -- seconds) because all actions run in parallel. Even though results are -- available out of order they are ordered due to the config option: -- --
-- >>> f x = delay x >> return x -- -- >>> Stream.fold Fold.toList $ Stream.parMapM (Stream.ordered True) f $ Stream.fromList [3,2,1] -- 1 sec -- 2 sec -- 3 sec -- [3,2,1] --parMapM :: MonadAsync m => (Config -> Config) -> (a -> m b) -> Stream m a -> Stream m b -- | Definition: -- --
-- >>> parSequence modifier = Stream.parMapM modifier id ---- -- Useful idioms: -- --
-- >>> parFromListM = Stream.parSequence id . Stream.fromList -- -- >>> parFromFoldableM = Stream.parSequence id . StreamK.toStream . StreamK.fromFoldable --parSequence :: MonadAsync m => (Config -> Config) -> Stream m (m a) -> Stream m a -- | Binary operation to evaluate two streams concurrently using a channel. -- -- If you want to combine more than two streams you almost always want -- the parList or parConcat operation instead. The -- performance of this operation degrades rapidly when more streams are -- combined as each operation adds one more concurrent channel. On the -- other hand, parConcat uses a single channel for all streams. -- However, with this operation you can precisely control the scheduling -- by creating arbitrary shape expression trees. -- -- Definition: -- --
-- >>> parTwo cfg x y = Stream.parList cfg [x, y] ---- -- Example, the following code finishes in 4 seconds: -- --
-- >>> async = Stream.parTwo id -- -- >>> stream1 = Stream.fromEffect (delay 4) -- -- >>> stream2 = Stream.fromEffect (delay 2) -- -- >>> Stream.fold Fold.toList $ stream1 `async` stream2 -- 2 sec -- 4 sec -- [2,4] --parTwo :: MonadAsync m => (Config -> Config) -> Stream m a -> Stream m a -> Stream m a -- | Evaluates the streams being zipped in separate threads than the -- consumer. The zip function is evaluated in the consumer thread. -- --
-- >>> parZipWithM cfg f m1 m2 = Stream.zipWithM f (Stream.parEval cfg m1) (Stream.parEval cfg m2) ---- -- Multi-stream concurrency options won't apply here, see the notes in -- parEval. -- -- If you want to evaluate the zip function as well in a separate thread, -- you can use a parEval on parZipWithM. parZipWithM :: MonadAsync m => (Config -> Config) -> (a -> b -> m c) -> Stream m a -> Stream m b -> Stream m c -- |
-- >>> parZipWith cfg f = Stream.parZipWithM cfg (\a b -> return $ f a b) ---- --
-- >>> m1 = Stream.fromList [1,2,3] -- -- >>> m2 = Stream.fromList [4,5,6] -- -- >>> Stream.fold Fold.toList $ Stream.parZipWith id (,) m1 m2 -- [(1,4),(2,5),(3,6)] --parZipWith :: MonadAsync m => (Config -> Config) -> (a -> b -> c) -> Stream m a -> Stream m b -> Stream m c -- | Like mergeByM but evaluates both the streams concurrently. -- -- Definition: -- --
-- >>> parMergeByM cfg f m1 m2 = Stream.mergeByM f (Stream.parEval cfg m1) (Stream.parEval cfg m2) --parMergeByM :: MonadAsync m => (Config -> Config) -> (a -> a -> m Ordering) -> Stream m a -> Stream m a -> Stream m a -- | Like mergeBy but evaluates both the streams concurrently. -- -- Definition: -- --
-- >>> parMergeBy cfg f = Stream.parMergeByM cfg (\a b -> return $ f a b) --parMergeBy :: MonadAsync m => (Config -> Config) -> (a -> a -> Ordering) -> Stream m a -> Stream m a -> Stream m a -- | Like concat but works on a list of streams. -- --
-- >>> parListLazy = Stream.parList id --parListLazy :: MonadAsync m => [Stream m a] -> Stream m a -- | Like parListLazy but with ordered on. -- --
-- >>> parListOrdered = Stream.parList (Stream.ordered True) --parListOrdered :: MonadAsync m => [Stream m a] -> Stream m a -- | Like parListLazy but interleaves the streams fairly instead of -- prioritizing the left stream. This schedules all streams in a round -- robin fashion over limited number of threads. -- --
-- >>> parListInterleaved = Stream.parList (Stream.interleaved True) --parListInterleaved :: MonadAsync m => [Stream m a] -> Stream m a -- | Like parListLazy but with eager on. -- --
-- >>> parListEager = Stream.parList (Stream.eager True) --parListEager :: MonadAsync m => [Stream m a] -> Stream m a -- | Like parListEager but stops the output as soon as the first -- stream stops. -- --
-- >>> parListEagerFst = Stream.parList (Stream.eager True . Stream.stopWhen Stream.FirstStops) --parListEagerFst :: MonadAsync m => [Stream m a] -> Stream m a -- | Like parListEager but stops the output as soon as any of the -- two streams stops. -- -- Definition: -- --
-- >>> parListEagerMin = Stream.parList (Stream.eager True . Stream.stopWhen Stream.AnyStops) --parListEagerMin :: MonadAsync m => [Stream m a] -> Stream m a -- | Like parConcat but works on a list of streams. -- --
-- >>> parList modifier = Stream.parConcat modifier . Stream.fromList --parList :: MonadAsync m => (Config -> Config) -> [Stream m a] -> Stream m a -- | Apply an argument stream to a function stream concurrently. Uses a -- shared channel for all individual applications within a stream -- application. parApply :: MonadAsync m => (Config -> Config) -> Stream m (a -> b) -> Stream m a -> Stream m b -- | Evaluate the streams in the input stream concurrently and combine -- them. -- --
-- >>> parConcat modifier = Stream.parConcatMap modifier id --parConcat :: MonadAsync m => (Config -> Config) -> Stream m (Stream m a) -> Stream m a -- | Map each element of the input to a stream and then concurrently -- evaluate and concatenate the resulting streams. Multiple streams may -- be evaluated concurrently but earlier streams are perferred. Output -- from the streams are used as they arrive. -- -- Definition: -- --
-- >>> parConcatMap modifier f stream = Stream.parConcat modifier $ fmap f stream ---- -- Examples: -- --
-- >>> f cfg xs = Stream.fold Fold.toList $ Stream.parConcatMap cfg id $ Stream.fromList xs ---- -- The following streams finish in 4 seconds: -- --
-- >>> stream1 = Stream.fromEffect (delay 4) -- -- >>> stream2 = Stream.fromEffect (delay 2) -- -- >>> stream3 = Stream.fromEffect (delay 1) -- -- >>> f id [stream1, stream2, stream3] -- 1 sec -- 2 sec -- 4 sec -- [1,2,4] ---- -- Limiting threads to 2 schedules the third stream only after one of the -- first two has finished, releasing a thread: -- --
-- >>> f (Stream.maxThreads 2) [stream1, stream2, stream3] -- ... -- [2,1,4] ---- -- When used with a Single thread it behaves like serial concatMap: -- --
-- >>> f (Stream.maxThreads 1) [stream1, stream2, stream3] -- ... -- [4,2,1] ---- --
-- >>> stream1 = Stream.fromList [1,2,3] -- -- >>> stream2 = Stream.fromList [4,5,6] -- -- >>> f (Stream.maxThreads 1) [stream1, stream2] -- [1,2,3,4,5,6] ---- -- Schedule all streams in a round robin fashion over the available -- threads: -- --
-- >>> f cfg xs = Stream.fold Fold.toList $ Stream.parConcatMap (Stream.interleaved True . cfg) id $ Stream.fromList xs ---- --
-- >>> stream1 = Stream.fromList [1,2,3] -- -- >>> stream2 = Stream.fromList [4,5,6] -- -- >>> f (Stream.maxThreads 1) [stream1, stream2] -- [1,4,2,5,3,6] --parConcatMap :: MonadAsync m => (Config -> Config) -> (a -> Stream m b) -> Stream m a -> Stream m b -- | Same as concatIterate but concurrent. -- -- Pre-release parConcatIterate :: MonadAsync m => (Config -> Config) -> (a -> Stream m a) -> Stream m a -> Stream m a -- | fromCallback f creates an entangled pair of a callback and a -- stream i.e. whenever the callback is called a value appears in the -- stream. The function f is invoked with the callback as -- argument, and the stream is returned. f would store the -- callback for calling it later for generating values in the stream. -- -- The callback queues a value to a concurrent channel associated with -- the stream. The stream can be evaluated safely in any thread. -- -- Pre-release fromCallback :: MonadAsync m => ((a -> m ()) -> m ()) -> Stream m a -- | parTapCount predicate fold stream taps the count of those -- elements in the stream that pass the predicate. The resulting -- count stream is sent to a fold running concurrently in -- another thread. -- -- For example, to print the count of elements processed every second: -- --
-- >>> rate = Stream.rollingMap2 (flip (-)) . Stream.delayPost 1 -- -- >>> report = Stream.fold (Fold.drainMapM print) . rate -- -- >>> tap = Stream.parTapCount (const True) report -- -- >>> go = Stream.fold Fold.drain $ tap $ Stream.enumerateFrom 0 ---- -- Note: This may not work correctly on 32-bit machines because of Int -- overflow. -- -- Pre-release parTapCount :: MonadAsync m => (a -> Bool) -> (Stream m Int -> m b) -> Stream m a -> Stream m a -- | Same as parTapCount. Deprecated. -- | Deprecated: Please use parTapCount instead. tapCount :: MonadAsync m => (a -> Bool) -> (Stream m Int -> m b) -> Stream m a -> Stream m a -- | Generate a stream by running an action periodically at the specified -- time interval. periodic :: MonadIO m => m a -> Double -> Stream m a -- | Generate a tick stream consisting of () elements, each tick -- is generated after the specified time delay given in seconds. -- --
-- >>> ticks = Stream.periodic (return ()) --ticks :: MonadIO m => Double -> Stream m () -- | Generate a tick stream, ticks are generated at the specified -- Rate. The rate is adaptive, the tick generation speed can be -- increased or decreased at different times to achieve the specified -- rate. The specific behavior for different styles of Rate -- specifications is documented under Rate. The effective maximum -- rate achieved by a stream is governed by the processor speed. -- --
-- >>> tickStream = Stream.repeatM (return ()) -- -- >>> ticksRate r = Stream.parEval (Stream.rate (Just r)) tickStream --ticksRate :: MonadAsync m => Rate -> Stream m () -- | Intersperse a monadic action into the input stream after every -- n seconds. -- -- Definition: -- --
-- >>> interject n f xs = Stream.parListEagerFst [xs, Stream.periodic f n] ---- -- Example: -- --
-- >>> s = Stream.fromList "hello" -- -- >>> input = Stream.mapM (\x -> threadDelay 1000000 >> putChar x) s -- -- >>> Stream.fold Fold.drain $ Stream.interject (putChar ',') 1.05 input -- h,e,l,l,o --interject :: MonadAsync m => m a -> Double -> Stream m a -> Stream m a -- | takeInterval interval runs the stream only upto the specified -- time interval in seconds. -- -- The interval starts when the stream is evaluated for the first time. takeInterval :: MonadAsync m => Double -> Stream m a -> Stream m a -- | Take time interval i seconds at the end of the stream. -- -- O(n) space, where n is the number elements taken. -- -- Unimplemented takeLastInterval :: Double -> Stream m a -> Stream m a -- | dropInterval interval drops all the stream elements that are -- generated before the specified interval in seconds has -- passed. -- -- The interval begins when the stream is evaluated for the first time. dropInterval :: MonadAsync m => Double -> Stream m a -> Stream m a -- | Drop time interval i seconds at the end of the stream. -- -- O(n) space, where n is the number elements dropped. -- -- Unimplemented dropLastInterval :: Int -> Stream m a -> Stream m a -- | Group the input stream into windows of n second each and then -- fold each group using the provided fold function. -- --
-- >>> twoPerSec = Stream.parEval (Stream.constRate 2) $ Stream.enumerateFrom 1 -- -- >>> intervals = Stream.intervalsOf 1 Fold.toList twoPerSec -- -- >>> Stream.fold Fold.toList $ Stream.take 2 intervals -- [...,...] --intervalsOf :: MonadAsync m => Double -> Fold m a b -> Stream m a -> Stream m b -- | Like chunksOf but if the chunk is not completed within the -- specified time interval then emit whatever we have collected till now. -- The chunk timeout is reset whenever a chunk is emitted. The -- granularity of the clock is 100 ms. -- --
-- >>> s = Stream.delayPost 0.3 $ Stream.fromList [1..1000] -- -- >>> f = Stream.fold (Fold.drainMapM print) $ Stream.groupsOfTimeout 5 1 Fold.toList s ---- -- Pre-release groupsOfTimeout :: MonadAsync m => Int -> Double -> Fold m a b -> Stream m a -> Stream m b -- | Continuously evaluate the input stream and sample the last event in -- each time window of n seconds. -- -- This is also known as throttle in some libraries. -- --
-- >>> sampleIntervalEnd n = Stream.catMaybes . Stream.intervalsOf n Fold.latest --sampleIntervalEnd :: MonadAsync m => Double -> Stream m a -> Stream m a -- | Like sampleInterval but samples at the beginning of the time -- window. -- --
-- >>> sampleIntervalStart n = Stream.catMaybes . Stream.intervalsOf n Fold.one --sampleIntervalStart :: MonadAsync m => Double -> Stream m a -> Stream m a sampleBurst :: MonadAsync m => Bool -> Double -> Stream m a -> Stream m a -- | Sample one event at the end of each burst of events. A burst is a -- group of events close together in time, it ends when an event is -- spaced by more than the specified time interval (in seconds) from the -- previous event. -- -- This is known as debounce in some libraries. -- -- The clock granularity is 10 ms. sampleBurstEnd :: MonadAsync m => Double -> Stream m a -> Stream m a -- | Like sampleBurstEnd but samples the event at the beginning of -- the burst instead of at the end of it. sampleBurstStart :: MonadAsync m => Double -> Stream m a -> Stream m a classifySessionsByGeneric :: forall m f a b. (MonadAsync m, IsMap f) => Proxy (f :: Type -> Type) -> Double -> Bool -> (Int -> m Bool) -> Double -> Fold m a b -> Stream m (AbsTime, (Key f, a)) -> Stream m (Key f, b) -- | classifySessionsBy tick keepalive predicate timeout fold -- stream classifies an input event stream consisting of -- (timestamp, (key, value)) into sessions based on the -- key, folding all the values corresponding to the same key -- into a session using the supplied fold. -- -- When the fold terminates or a timeout occurs, a tuple -- consisting of the session key and the folded value is emitted in the -- output stream. The timeout is measured from the first event in the -- session. If the keepalive option is set to True the -- timeout is reset to 0 whenever an event is received. -- -- The timestamp in the input stream is an absolute time from -- some epoch, characterizing the time when the input event was -- generated. The notion of current time is maintained by a monotonic -- event time clock using the timestamps seen in the input stream. The -- latest timestamp seen till now is used as the base for the current -- time. When no new events are seen, a timer is started with a clock -- resolution of tick seconds. This timer is used to detect -- session timeouts in the absence of new events. -- -- To ensure an upper bound on the memory used the number of sessions can -- be limited to an upper bound. If the ejection predicate -- returns True, the oldest session is ejected before inserting a -- new session. -- -- When the stream ends any buffered sessions are ejected immediately. -- -- If a session key is received even after a session has finished, -- another session is created for that key. -- --
-- >>> :{ -- Stream.fold (Fold.drainMapM print) -- $ Stream.classifySessionsBy 1 False (const (return False)) 3 (Fold.take 3 Fold.toList) -- $ Stream.timestamped -- $ Stream.delay 0.1 -- $ Stream.fromList ((,) <$> [1,2,3] <*> ['a','b','c']) -- :} -- (1,"abc") -- (2,"abc") -- (3,"abc") ---- -- Pre-release classifySessionsBy :: (MonadAsync m, Ord k) => Double -> Bool -> (Int -> m Bool) -> Double -> Fold m a b -> Stream m (AbsTime, (k, a)) -> Stream m (k, b) -- | Same as classifySessionsBy with a timer tick of 1 second and -- keepalive option set to False. -- --
-- >>> classifySessionsOf = Stream.classifySessionsBy 1 False ---- -- Pre-release classifySessionsOf :: (MonadAsync m, Ord k) => (Int -> m Bool) -> Double -> Fold m a b -> Stream m (AbsTime, (k, a)) -> Stream m (k, b) -- | Same as classifySessionsBy with a timer tick of 1 second and -- keepalive option set to True. -- --
-- classifyKeepAliveSessions = classifySessionsBy 1 True ---- -- Pre-release classifyKeepAliveSessions :: (MonadAsync m, Ord k) => (Int -> m Bool) -> Double -> Fold m a b -> Stream m (AbsTime, (k, a)) -> Stream m (k, b) -- | Always produce the latest available element from the stream without -- any delay. The stream is continuously evaluated at the highest -- possible rate and only the latest element is retained for sampling. -- -- Unimplemented bufferLatest :: Stream m a -> Stream m (Maybe a) -- | Evaluate the input stream continuously and keep only the latest -- n elements in a ring buffer, keep discarding the older ones -- to make space for the new ones. When the output stream is evaluated -- the buffer collected till now is streamed and it starts filling again. -- -- Unimplemented bufferLatestN :: Int -> Stream m a -> Stream m a -- | Evaluate the input stream continuously and keep only the oldest -- n elements in the buffer, discard the new ones when the -- buffer is full. When the output stream is evaluated the collected -- buffer is streamed and the buffer starts filling again. -- -- Unimplemented bufferOldestN :: Int -> Stream m a -> Stream m a -- | Run the action m b whenever the stream Stream m a -- stops normally, or if it is garbage collected after a partial lazy -- evaluation. -- -- The semantics of the action m b are similar to the semantics -- of cleanup action in bracket. -- -- See also after_ after :: (MonadIO m, MonadBaseControl IO m) => m b -> Stream m a -> Stream m a -- | Run the alloc action IO b with async exceptions disabled but -- keeping blocking operations interruptible (see mask). Use the -- output b of the IO action as input to the function b -- -> Stream m a to generate an output stream. -- -- b is usually a resource under the IO monad, e.g. a file -- handle, that requires a cleanup after use. The cleanup action b -- -> m c, runs whenever (1) the stream ends normally, (2) due to -- a sync or async exception or, (3) if it gets garbage collected after a -- partial lazy evaluation. The exception is not caught, it is rethrown. -- -- bracket only guarantees that the cleanup action runs, and it -- runs with async exceptions enabled. The action must ensure that it can -- successfully cleanup the resource in the face of sync or async -- exceptions. -- -- When the stream ends normally or on a sync exception, cleanup action -- runs immediately in the current thread context, whereas in other cases -- it runs in the GC context, therefore, cleanup may be delayed until the -- GC gets to run. -- -- See also: bracket_ -- -- Inhibits stream fusion bracket :: (MonadAsync m, MonadCatch m) => m b -> (b -> m c) -> (b -> Stream m a) -> Stream m a -- | Like bracket but can use 3 separate cleanup actions depending -- on the mode of termination: -- --
-- >>> finally action xs = Stream.bracket (return ()) (const action) (const xs) ---- -- See also finally_ -- -- Inhibits stream fusion finally :: (MonadAsync m, MonadCatch m) => m b -> Stream m a -> Stream m a -- | retry takes 3 arguments -- --
-- >>> parUnfoldrM step = Stream.parEval id . Stream.unfoldrM step -- -- >>> parIterateM step = Stream.parEval id . Stream.iterateM step --parEval :: MonadAsync m => (Config -> Config) -> Stream m a -> Stream m a -- | Definition: -- --
-- >>> parRepeatM cfg = Stream.parSequence cfg . Stream.repeat ---- -- Generate a stream by repeatedly executing a monadic action forever. parRepeatM :: MonadAsync m => (Config -> Config) -> m a -> Stream m a -- | Generate a stream by concurrently performing a monadic action -- n times. -- -- Definition: -- --
-- >>> parReplicateM cfg n = Stream.parSequence cfg . Stream.replicate n ---- -- Example, parReplicateM in the following example executes all -- the replicated actions concurrently, thus taking only 1 second: -- --
-- >>> Stream.fold Fold.drain $ Stream.parReplicateM id 10 $ delay 1 -- ... --parReplicateM :: MonadAsync m => (Config -> Config) -> Int -> m a -> Stream m a -- | fromCallback f creates an entangled pair of a callback and a -- stream i.e. whenever the callback is called a value appears in the -- stream. The function f is invoked with the callback as -- argument, and the stream is returned. f would store the -- callback for calling it later for generating values in the stream. -- -- The callback queues a value to a concurrent channel associated with -- the stream. The stream can be evaluated safely in any thread. -- -- Pre-release fromCallback :: MonadAsync m => ((a -> m ()) -> m ()) -> Stream m a -- | Definition: -- --
-- >>> parMapM modifier f = Stream.parConcatMap modifier (Stream.fromEffect . f) ---- -- For example, the following finishes in 3 seconds (as opposed to 6 -- seconds) because all actions run in parallel. Even though results are -- available out of order they are ordered due to the config option: -- --
-- >>> f x = delay x >> return x -- -- >>> Stream.fold Fold.toList $ Stream.parMapM (Stream.ordered True) f $ Stream.fromList [3,2,1] -- 1 sec -- 2 sec -- 3 sec -- [3,2,1] --parMapM :: MonadAsync m => (Config -> Config) -> (a -> m b) -> Stream m a -> Stream m b -- | Definition: -- --
-- >>> parSequence modifier = Stream.parMapM modifier id ---- -- Useful idioms: -- --
-- >>> parFromListM = Stream.parSequence id . Stream.fromList -- -- >>> parFromFoldableM = Stream.parSequence id . StreamK.toStream . StreamK.fromFoldable --parSequence :: MonadAsync m => (Config -> Config) -> Stream m (m a) -> Stream m a -- | Evaluates the streams being zipped in separate threads than the -- consumer. The zip function is evaluated in the consumer thread. -- --
-- >>> parZipWithM cfg f m1 m2 = Stream.zipWithM f (Stream.parEval cfg m1) (Stream.parEval cfg m2) ---- -- Multi-stream concurrency options won't apply here, see the notes in -- parEval. -- -- If you want to evaluate the zip function as well in a separate thread, -- you can use a parEval on parZipWithM. parZipWithM :: MonadAsync m => (Config -> Config) -> (a -> b -> m c) -> Stream m a -> Stream m b -> Stream m c -- |
-- >>> parZipWith cfg f = Stream.parZipWithM cfg (\a b -> return $ f a b) ---- --
-- >>> m1 = Stream.fromList [1,2,3] -- -- >>> m2 = Stream.fromList [4,5,6] -- -- >>> Stream.fold Fold.toList $ Stream.parZipWith id (,) m1 m2 -- [(1,4),(2,5),(3,6)] --parZipWith :: MonadAsync m => (Config -> Config) -> (a -> b -> c) -> Stream m a -> Stream m b -> Stream m c -- | Like mergeByM but evaluates both the streams concurrently. -- -- Definition: -- --
-- >>> parMergeByM cfg f m1 m2 = Stream.mergeByM f (Stream.parEval cfg m1) (Stream.parEval cfg m2) --parMergeByM :: MonadAsync m => (Config -> Config) -> (a -> a -> m Ordering) -> Stream m a -> Stream m a -> Stream m a -- | Like mergeBy but evaluates both the streams concurrently. -- -- Definition: -- --
-- >>> parMergeBy cfg f = Stream.parMergeByM cfg (\a b -> return $ f a b) --parMergeBy :: MonadAsync m => (Config -> Config) -> (a -> a -> Ordering) -> Stream m a -> Stream m a -> Stream m a -- | Like parConcat but works on a list of streams. -- --
-- >>> parList modifier = Stream.parConcat modifier . Stream.fromList --parList :: MonadAsync m => (Config -> Config) -> [Stream m a] -> Stream m a -- | Apply an argument stream to a function stream concurrently. Uses a -- shared channel for all individual applications within a stream -- application. parApply :: MonadAsync m => (Config -> Config) -> Stream m (a -> b) -> Stream m a -> Stream m b -- | Evaluate the streams in the input stream concurrently and combine -- them. -- --
-- >>> parConcat modifier = Stream.parConcatMap modifier id --parConcat :: MonadAsync m => (Config -> Config) -> Stream m (Stream m a) -> Stream m a -- | Map each element of the input to a stream and then concurrently -- evaluate and concatenate the resulting streams. Multiple streams may -- be evaluated concurrently but earlier streams are perferred. Output -- from the streams are used as they arrive. -- -- Definition: -- --
-- >>> parConcatMap modifier f stream = Stream.parConcat modifier $ fmap f stream ---- -- Examples: -- --
-- >>> f cfg xs = Stream.fold Fold.toList $ Stream.parConcatMap cfg id $ Stream.fromList xs ---- -- The following streams finish in 4 seconds: -- --
-- >>> stream1 = Stream.fromEffect (delay 4) -- -- >>> stream2 = Stream.fromEffect (delay 2) -- -- >>> stream3 = Stream.fromEffect (delay 1) -- -- >>> f id [stream1, stream2, stream3] -- 1 sec -- 2 sec -- 4 sec -- [1,2,4] ---- -- Limiting threads to 2 schedules the third stream only after one of the -- first two has finished, releasing a thread: -- --
-- >>> f (Stream.maxThreads 2) [stream1, stream2, stream3] -- ... -- [2,1,4] ---- -- When used with a Single thread it behaves like serial concatMap: -- --
-- >>> f (Stream.maxThreads 1) [stream1, stream2, stream3] -- ... -- [4,2,1] ---- --
-- >>> stream1 = Stream.fromList [1,2,3] -- -- >>> stream2 = Stream.fromList [4,5,6] -- -- >>> f (Stream.maxThreads 1) [stream1, stream2] -- [1,2,3,4,5,6] ---- -- Schedule all streams in a round robin fashion over the available -- threads: -- --
-- >>> f cfg xs = Stream.fold Fold.toList $ Stream.parConcatMap (Stream.interleaved True . cfg) id $ Stream.fromList xs ---- --
-- >>> stream1 = Stream.fromList [1,2,3] -- -- >>> stream2 = Stream.fromList [4,5,6] -- -- >>> f (Stream.maxThreads 1) [stream1, stream2] -- [1,4,2,5,3,6] --parConcatMap :: MonadAsync m => (Config -> Config) -> (a -> Stream m b) -> Stream m a -> Stream m b -- | Same as concatIterate but concurrent. -- -- Pre-release parConcatIterate :: MonadAsync m => (Config -> Config) -> (a -> Stream m a) -> Stream m a -> Stream m a -- | parTapCount predicate fold stream taps the count of those -- elements in the stream that pass the predicate. The resulting -- count stream is sent to a fold running concurrently in -- another thread. -- -- For example, to print the count of elements processed every second: -- --
-- >>> rate = Stream.rollingMap2 (flip (-)) . Stream.delayPost 1 -- -- >>> report = Stream.fold (Fold.drainMapM print) . rate -- -- >>> tap = Stream.parTapCount (const True) report -- -- >>> go = Stream.fold Fold.drain $ tap $ Stream.enumerateFrom 0 ---- -- Note: This may not work correctly on 32-bit machines because of Int -- overflow. -- -- Pre-release parTapCount :: MonadAsync m => (a -> Bool) -> (Stream m Int -> m b) -> Stream m a -> Stream m a -- | Intersperse a monadic action into the input stream after every -- n seconds. -- -- Definition: -- --
-- >>> interject n f xs = Stream.parListEagerFst [xs, Stream.periodic f n] ---- -- Example: -- --
-- >>> s = Stream.fromList "hello" -- -- >>> input = Stream.mapM (\x -> threadDelay 1000000 >> putChar x) s -- -- >>> Stream.fold Fold.drain $ Stream.interject (putChar ',') 1.05 input -- h,e,l,l,o --interject :: MonadAsync m => m a -> Double -> Stream m a -> Stream m a -- | takeInterval interval runs the stream only upto the specified -- time interval in seconds. -- -- The interval starts when the stream is evaluated for the first time. takeInterval :: MonadAsync m => Double -> Stream m a -> Stream m a -- | dropInterval interval drops all the stream elements that are -- generated before the specified interval in seconds has -- passed. -- -- The interval begins when the stream is evaluated for the first time. dropInterval :: MonadAsync m => Double -> Stream m a -> Stream m a -- | Group the input stream into windows of n second each and then -- fold each group using the provided fold function. -- --
-- >>> twoPerSec = Stream.parEval (Stream.constRate 2) $ Stream.enumerateFrom 1 -- -- >>> intervals = Stream.intervalsOf 1 Fold.toList twoPerSec -- -- >>> Stream.fold Fold.toList $ Stream.take 2 intervals -- [...,...] --intervalsOf :: MonadAsync m => Double -> Fold m a b -> Stream m a -> Stream m b -- | Continuously evaluate the input stream and sample the last event in -- each time window of n seconds. -- -- This is also known as throttle in some libraries. -- --
-- >>> sampleIntervalEnd n = Stream.catMaybes . Stream.intervalsOf n Fold.latest --sampleIntervalEnd :: MonadAsync m => Double -> Stream m a -> Stream m a -- | Like sampleInterval but samples at the beginning of the time -- window. -- --
-- >>> sampleIntervalStart n = Stream.catMaybes . Stream.intervalsOf n Fold.one --sampleIntervalStart :: MonadAsync m => Double -> Stream m a -> Stream m a -- | Sample one event at the end of each burst of events. A burst is a -- group of events close together in time, it ends when an event is -- spaced by more than the specified time interval (in seconds) from the -- previous event. -- -- This is known as debounce in some libraries. -- -- The clock granularity is 10 ms. sampleBurstEnd :: MonadAsync m => Double -> Stream m a -> Stream m a -- | Like sampleBurstEnd but samples the event at the beginning of -- the burst instead of at the end of it. sampleBurstStart :: MonadAsync m => Double -> Stream m a -> Stream m a -- | Run the action m b whenever the stream Stream m a -- stops normally, or if it is garbage collected after a partial lazy -- evaluation. -- -- The semantics of the action m b are similar to the semantics -- of cleanup action in bracket. -- -- See also after_ after :: (MonadIO m, MonadBaseControl IO m) => m b -> Stream m a -> Stream m a -- | Run the alloc action IO b with async exceptions disabled but -- keeping blocking operations interruptible (see mask). Use the -- output b of the IO action as input to the function b -- -> Stream m a to generate an output stream. -- -- b is usually a resource under the IO monad, e.g. a file -- handle, that requires a cleanup after use. The cleanup action b -- -> m c, runs whenever (1) the stream ends normally, (2) due to -- a sync or async exception or, (3) if it gets garbage collected after a -- partial lazy evaluation. The exception is not caught, it is rethrown. -- -- bracket only guarantees that the cleanup action runs, and it -- runs with async exceptions enabled. The action must ensure that it can -- successfully cleanup the resource in the face of sync or async -- exceptions. -- -- When the stream ends normally or on a sync exception, cleanup action -- runs immediately in the current thread context, whereas in other cases -- it runs in the GC context, therefore, cleanup may be delayed until the -- GC gets to run. -- -- See also: bracket_ -- -- Inhibits stream fusion bracket :: (MonadAsync m, MonadCatch m) => m b -> (b -> m c) -> (b -> Stream m a) -> Stream m a -- | Run the action m b whenever the stream Stream m a -- stops normally, aborts due to an exception or if it is garbage -- collected after a partial lazy evaluation. -- -- The semantics of running the action m b are similar to the -- cleanup action semantics described in bracket. -- --
-- >>> finally action xs = Stream.bracket (return ()) (const action) (const xs) ---- -- See also finally_ -- -- Inhibits stream fusion finally :: (MonadAsync m, MonadCatch m) => m b -> Stream m a -> Stream m a -- | Same as parTapCount. Deprecated. -- | Deprecated: Please use parTapCount instead. tapCount :: MonadAsync m => (a -> Bool) -> (Stream m Int -> m b) -> Stream m a -> Stream m a -- | To run examples in this module: -- --
-- >>> import qualified Streamly.Prelude as Stream -- -- >>> import qualified Streamly.Internal.Data.Stream as D -- -- >>> import qualified Streamly.Data.Fold as Fold ---- | Deprecated: Use Streamly.Data.Stream.MkType instead. module Streamly.Internal.Data.Stream.Zip -- | For ZipSerialM streams: -- --
-- (<>) = serial -- (*) = 'Streamly.Prelude.serial.zipWith' id ---- -- Applicative evaluates the streams being zipped serially: -- --
-- >>> s1 = Stream.fromFoldable [1, 2] -- -- >>> s2 = Stream.fromFoldable [3, 4] -- -- >>> s3 = Stream.fromFoldable [5, 6] -- -- >>> Stream.toList $ Stream.fromZipSerial $ (,,) <$> s1 <*> s2 <*> s3 -- [(1,3,5),(2,4,6)] ---- -- Since: 0.2.0 (Streamly) newtype ZipSerialM m a ZipSerialM :: Stream m a -> ZipSerialM m a [getZipSerialM] :: ZipSerialM m a -> Stream m a -- | An IO stream whose applicative instance zips streams serially. -- -- Since: 0.2.0 (Streamly) type ZipSerial = ZipSerialM IO consMZip :: Monad m => m a -> ZipSerialM m a -> ZipSerialM m a zipWithK :: Monad m => (a -> b -> c) -> Stream m a -> Stream m b -> Stream m c zipWithMK :: Monad m => (a -> b -> m c) -> Stream m a -> Stream m b -> Stream m c newtype ZipConcurrent m a ZipConcurrent :: Stream m a -> ZipConcurrent m a [getZipConcurrent] :: ZipConcurrent m a -> Stream m a type ZipStream = ZipSerialM instance GHC.Base.Monoid (Streamly.Internal.Data.Stream.Zip.ZipSerialM m a) instance GHC.Base.Semigroup (Streamly.Internal.Data.Stream.Zip.ZipSerialM m a) instance GHC.Base.Monad m => GHC.Base.Functor (Streamly.Internal.Data.Stream.Zip.ZipConcurrent m) instance Streamly.Internal.Control.Concurrent.MonadAsync m => GHC.Base.Applicative (Streamly.Internal.Data.Stream.Zip.ZipConcurrent m) instance GHC.Exts.IsList (Streamly.Internal.Data.Stream.Zip.ZipSerialM Data.Functor.Identity.Identity a) instance GHC.Classes.Eq a => GHC.Classes.Eq (Streamly.Internal.Data.Stream.Zip.ZipSerialM Data.Functor.Identity.Identity a) instance GHC.Classes.Ord a => GHC.Classes.Ord (Streamly.Internal.Data.Stream.Zip.ZipSerialM Data.Functor.Identity.Identity a) instance GHC.Show.Show a => GHC.Show.Show (Streamly.Internal.Data.Stream.Zip.ZipSerialM Data.Functor.Identity.Identity a) instance GHC.Read.Read a => GHC.Read.Read (Streamly.Internal.Data.Stream.Zip.ZipSerialM Data.Functor.Identity.Identity a) instance (a GHC.Types.~ GHC.Types.Char) => Data.String.IsString (Streamly.Internal.Data.Stream.Zip.ZipSerialM Data.Functor.Identity.Identity a) instance Control.DeepSeq.NFData a => Control.DeepSeq.NFData (Streamly.Internal.Data.Stream.Zip.ZipSerialM Data.Functor.Identity.Identity a) instance Control.DeepSeq.NFData1 (Streamly.Internal.Data.Stream.Zip.ZipSerialM Data.Functor.Identity.Identity) instance GHC.Base.Monad m => GHC.Base.Functor (Streamly.Internal.Data.Stream.Zip.ZipSerialM m) instance GHC.Base.Monad m => GHC.Base.Applicative (Streamly.Internal.Data.Stream.Zip.ZipSerialM m) instance (Data.Foldable.Foldable m, GHC.Base.Monad m) => Data.Foldable.Foldable (Streamly.Internal.Data.Stream.Zip.ZipSerialM m) instance Data.Traversable.Traversable (Streamly.Internal.Data.Stream.Zip.ZipSerialM Data.Functor.Identity.Identity) -- | To run examples in this module: -- --
-- >>> import qualified Streamly.Prelude as Stream ---- | Deprecated: Use Streamly.Data.Stream.MkType instead. module Streamly.Internal.Data.Stream.ZipAsync -- | For ZipAsyncM streams: -- --
-- (<>) = serial -- (*) = 'Streamly.Prelude.serial.zipAsyncWith' id ---- -- Applicative evaluates the streams being zipped concurrently, the -- following would take half the time that it would take in serial -- zipping: -- --
-- >>> s = Stream.fromFoldableM $ Prelude.map delay [1, 1, 1] -- -- >>> Stream.toList $ Stream.fromZipAsync $ (,) <$> s <*> s -- ... -- [(1,1),(1,1),(1,1)] ---- -- Since: 0.2.0 (Streamly) newtype ZipAsyncM m a ZipAsyncM :: Stream m a -> ZipAsyncM m a [getZipAsyncM] :: ZipAsyncM m a -> Stream m a -- | An IO stream whose applicative instance zips streams wAsyncly. -- -- Since: 0.2.0 (Streamly) type ZipAsync = ZipAsyncM IO consMZipAsync :: Monad m => m a -> ZipAsyncM m a -> ZipAsyncM m a -- | Like zipWith but zips concurrently i.e. both the streams -- being zipped are evaluated concurrently using the ParallelT -- concurrent evaluation style. The maximum number of elements of each -- stream evaluated in advance can be controlled by maxBuffer. -- -- The stream ends if stream a or stream b ends. -- However, if stream b ends while we are still evaluating -- stream a and waiting for a result then stream will not end -- until after the evaluation of stream a finishes. This -- behavior can potentially be changed in future to end the stream -- immediately as soon as any of the stream end is detected. zipAsyncWithK :: MonadAsync m => (a -> b -> c) -> Stream m a -> Stream m b -> Stream m c -- | Like zipAsyncWith but with a monadic zipping function. zipAsyncWithMK :: MonadAsync m => (a -> b -> m c) -> Stream m a -> Stream m b -> Stream m c instance GHC.Base.Monoid (Streamly.Internal.Data.Stream.ZipAsync.ZipAsyncM m a) instance GHC.Base.Semigroup (Streamly.Internal.Data.Stream.ZipAsync.ZipAsyncM m a) instance GHC.Base.Monad m => GHC.Base.Functor (Streamly.Internal.Data.Stream.ZipAsync.ZipAsyncM m) instance Streamly.Internal.Control.Concurrent.MonadAsync m => GHC.Base.Applicative (Streamly.Internal.Data.Stream.ZipAsync.ZipAsyncM m) -- | This is an internal module which is a superset of the corresponding -- released module Streamly.Prelude. It contains some additional -- unreleased or experimental APIs. -- | Deprecated: Please use "Streamly.Internal.Data.Stream from -- streamly-core package", -- Streamly.Internal.Data.Stream.Concurrent, -- Streamly.Internal.Data.Stream.Exception.Lifted, & -- Streamly.Internal.Data.Stream.Time from streamly package -- instead. module Streamly.Internal.Data.Stream.IsStream newtype StreamK (m :: Type -> Type) a MkStream :: (forall r. () => State StreamK m a -> (a -> StreamK m a -> m r) -> (a -> m r) -> m r -> m r) -> StreamK (m :: Type -> Type) a -- | An interleaving serial IO stream of elements of type a. See -- WSerialT documentation for more details. -- -- Since: 0.2.0 (Streamly) type WSerial = WSerialT IO -- | For WSerialT streams: -- --
-- (<>) = wSerial -- Semigroup -- (>>=) = flip . concatMapWith wSerial -- Monad ---- -- Note that <> is associative only if we disregard the -- ordering of elements in the resulting stream. -- -- A single Monad bind behaves like a for loop: -- --
-- >>> :{ -- IsStream.toList $ IsStream.fromWSerial $ do -- x <- IsStream.fromList [1,2] -- foreach x in stream -- return x -- :} -- [1,2] ---- -- Nested monad binds behave like interleaved nested for loops: -- --
-- >>> :{ -- IsStream.toList $ IsStream.fromWSerial $ do -- x <- IsStream.fromList [1,2] -- foreach x in stream -- y <- IsStream.fromList [3,4] -- foreach y in stream -- return (x, y) -- :} -- [(1,3),(2,3),(1,4),(2,4)] ---- -- It is a result of interleaving all the nested iterations corresponding -- to element 1 in the first stream with all the nested -- iterations of element 2: -- --
-- >>> import Streamly.Prelude (wSerial) -- -- >>> IsStream.toList $ IsStream.fromList [(1,3),(1,4)] `IsStream.wSerial` IsStream.fromList [(2,3),(2,4)] -- [(1,3),(2,3),(1,4),(2,4)] ---- -- The W in the name stands for wide or breadth wise -- scheduling in contrast to the depth wise scheduling behavior of -- SerialT. -- -- Since: 0.2.0 (Streamly) data WSerialT m a -- | A serial IO stream of elements of type a. See SerialT -- documentation for more details. -- -- Since: 0.2.0 (Streamly) type Serial = SerialT IO -- | For SerialT streams: -- --
-- (<>) = serial -- Semigroup -- (>>=) = flip . concatMapWith serial -- Monad ---- -- A single Monad bind behaves like a for loop: -- --
-- >>> :{ -- IsStream.toList $ do -- x <- IsStream.fromList [1,2] -- foreach x in stream -- return x -- :} -- [1,2] ---- -- Nested monad binds behave like nested for loops: -- --
-- >>> :{ -- IsStream.toList $ do -- x <- IsStream.fromList [1,2] -- foreach x in stream -- y <- IsStream.fromList [3,4] -- foreach y in stream -- return (x, y) -- :} -- [(1,3),(1,4),(2,3),(2,4)] ---- -- Since: 0.2.0 (Streamly) data SerialT m a -- | A parallely composing IO stream of elements of type a. See -- ParallelT documentation for more details. -- -- Since: 0.2.0 (Streamly) type Parallel = ParallelT IO -- | For ParallelT streams: -- --
-- (<>) = parallel -- (>>=) = flip . concatMapWith parallel ---- -- See AsyncT, ParallelT is similar except that all -- iterations are strictly concurrent while in AsyncT it depends -- on the consumer demand and available threads. See parallel -- for more details. -- -- Since: 0.1.0 (Streamly) -- -- Since: 0.7.0 (maxBuffer applies to ParallelT streams) data ParallelT m a -- | A round robin parallely composing IO stream of elements of type -- a. See WAsyncT documentation for more details. -- -- Since: 0.2.0 (Streamly) type WAsync = WAsyncT IO -- | For WAsyncT streams: -- --
-- (<>) = wAsync -- (>>=) = flip . concatMapWith wAsync ---- -- A single Monad bind behaves like a for loop with -- iterations of the loop executed concurrently a la the wAsync -- combinator, producing results and side effects of iterations out of -- order: -- --
-- >>> :{ -- Stream.toList $ Stream.fromWAsync $ do -- x <- Stream.fromList [2,1] -- foreach x in stream -- Stream.fromEffect $ delay x -- :} -- 1 sec -- 2 sec -- [1,2] ---- -- Nested monad binds behave like nested for loops with nested -- iterations executed concurrently, a la the wAsync combinator: -- --
-- >>> :{ -- Stream.toList $ Stream.fromWAsync $ do -- x <- Stream.fromList [1,2] -- foreach x in stream -- y <- Stream.fromList [2,4] -- foreach y in stream -- Stream.fromEffect $ delay (x + y) -- :} -- 3 sec -- 4 sec -- 5 sec -- 6 sec -- [3,4,5,6] ---- -- The behavior can be explained as follows. All the iterations -- corresponding to the element 1 in the first stream constitute -- one WAsyncT output stream and all the iterations corresponding -- to 2 constitute another WAsyncT output stream and -- these two output streams are merged using wAsync. -- -- The W in the name stands for wide or breadth wise -- scheduling in contrast to the depth wise scheduling behavior of -- AsyncT. -- -- Since: 0.2.0 (Streamly) data WAsyncT m a -- | A demand driven left biased parallely composing IO stream of elements -- of type a. See AsyncT documentation for more details. -- -- Since: 0.2.0 (Streamly) type Async = AsyncT IO -- | For AsyncT streams: -- --
-- (<>) = async -- (>>=) = flip . concatMapWith async ---- -- A single Monad bind behaves like a for loop with -- iterations of the loop executed concurrently a la the async -- combinator, producing results and side effects of iterations out of -- order: -- --
-- >>> :{ -- Stream.toList $ Stream.fromAsync $ do -- x <- Stream.fromList [2,1] -- foreach x in stream -- Stream.fromEffect $ delay x -- :} -- 1 sec -- 2 sec -- [1,2] ---- -- Nested monad binds behave like nested for loops with nested -- iterations executed concurrently, a la the async combinator: -- --
-- >>> :{ -- Stream.toList $ Stream.fromAsync $ do -- x <- Stream.fromList [1,2] -- foreach x in stream -- y <- Stream.fromList [2,4] -- foreach y in stream -- Stream.fromEffect $ delay (x + y) -- :} -- 3 sec -- 4 sec -- 5 sec -- 6 sec -- [3,4,5,6] ---- -- The behavior can be explained as follows. All the iterations -- corresponding to the element 1 in the first stream constitute -- one output stream and all the iterations corresponding to 2 -- constitute another output stream and these two output streams are -- merged using async. -- -- Since: 0.1.0 (Streamly) data AsyncT m a -- | A serial IO stream of elements of type a with concurrent -- lookahead. See AheadT documentation for more details. -- -- Since: 0.3.0 (Streamly) type Ahead = AheadT IO -- | For AheadT streams: -- --
-- (<>) = ahead -- (>>=) = flip . concatMapWith ahead ---- -- A single Monad bind behaves like a for loop with -- iterations executed concurrently, ahead of time, producing side -- effects of iterations out of order, but results in order: -- --
-- >>> :{ -- Stream.toList $ Stream.fromAhead $ do -- x <- Stream.fromList [2,1] -- foreach x in stream -- Stream.fromEffect $ delay x -- :} -- 1 sec -- 2 sec -- [2,1] ---- -- Nested monad binds behave like nested for loops with nested -- iterations executed concurrently, ahead of time: -- --
-- >>> :{ -- Stream.toList $ Stream.fromAhead $ do -- x <- Stream.fromList [1,2] -- foreach x in stream -- y <- Stream.fromList [2,4] -- foreach y in stream -- Stream.fromEffect $ delay (x + y) -- :} -- 3 sec -- 4 sec -- 5 sec -- 6 sec -- [3,5,4,6] ---- -- The behavior can be explained as follows. All the iterations -- corresponding to the element 1 in the first stream constitute -- one output stream and all the iterations corresponding to 2 -- constitute another output stream and these two output streams are -- merged using ahead. -- -- Since: 0.3.0 (Streamly) data AheadT m a -- | An IO stream whose applicative instance zips streams serially. -- -- Since: 0.2.0 (Streamly) type ZipSerial = ZipSerialM IO -- | For ZipSerialM streams: -- --
-- (<>) = serial -- (*) = 'Streamly.Prelude.serial.zipWith' id ---- -- Applicative evaluates the streams being zipped serially: -- --
-- >>> s1 = Stream.fromFoldable [1, 2] -- -- >>> s2 = Stream.fromFoldable [3, 4] -- -- >>> s3 = Stream.fromFoldable [5, 6] -- -- >>> Stream.toList $ Stream.fromZipSerial $ (,,) <$> s1 <*> s2 <*> s3 -- [(1,3,5),(2,4,6)] ---- -- Since: 0.2.0 (Streamly) data ZipSerialM m a -- | An IO stream whose applicative instance zips streams wAsyncly. -- -- Since: 0.2.0 (Streamly) type ZipAsync = ZipAsyncM IO -- | For ZipAsyncM streams: -- --
-- (<>) = serial -- (*) = 'Streamly.Prelude.serial.zipAsyncWith' id ---- -- Applicative evaluates the streams being zipped concurrently, the -- following would take half the time that it would take in serial -- zipping: -- --
-- >>> s = Stream.fromFoldableM $ Prelude.map delay [1, 1, 1] -- -- >>> Stream.toList $ Stream.fromZipAsync $ (,) <$> s <*> s -- ... -- [(1,1),(1,1),(1,1)] ---- -- Since: 0.2.0 (Streamly) data ZipAsyncM m a -- | Class of types that can represent a stream of elements of some type -- a in some monad m. -- -- Since: 0.2.0 (Streamly) class (forall m a. MonadAsync m => Semigroup (t m a), forall m a. MonadAsync m => Monoid (t m a), forall m. Monad m => Functor (t m), forall m. MonadAsync m => Applicative (t m)) => IsStream t -- | Constructs a stream by adding a monadic action at the head of an -- existing stream. For example: -- --
-- > toList $ getLine `consM` getLine `consM` nil -- hello -- world -- ["hello","world"] ---- -- Concurrent (do not use fromParallel to construct infinite -- streams) consM :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a -- | Operator equivalent of consM. We can read it as "parallel -- colon" to remember that | comes before :. -- --
-- > toList $ getLine |: getLine |: nil -- hello -- world -- ["hello","world"] ---- --
-- let delay = threadDelay 1000000 >> print 1 -- drain $ fromSerial $ delay |: delay |: delay |: nil -- drain $ fromParallel $ delay |: delay |: delay |: nil ---- -- Concurrent (do not use fromParallel to construct infinite -- streams) (|:) :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a infixr 5 `consM` infixr 5 |: toStreamK :: IsStream t => t m a -> StreamK m a fromStreamK :: IsStream t => StreamK m a -> t m a -- | Adapt any specific stream type to any other specific stream type. -- -- Since: 0.1.0 (Streamly) adapt :: (IsStream t1, IsStream t2) => t1 m a -> t2 m a fromStreamD :: (IsStream t, Monad m) => Stream m a -> t m a -- | Adapt a polymorphic consM operation to a StreamK cons operation toConsK :: IsStream t => (m a -> t m a -> t m a) -> m a -> StreamK m a -> StreamK m a toStreamD :: (IsStream t, Monad m) => t m a -> Stream m a -- |
-- fromList = foldr cons nil ---- -- Construct a stream from a list of pure values. This is more efficient -- than fromFoldable for serial streams. fromList :: (Monad m, IsStream t) => [a] -> t m a -- | Build a stream from an SVar, a stop continuation, a singleton -- stream continuation and a yield continuation. mkStream :: IsStream t => (forall r. State StreamK m a -> (a -> t m a -> m r) -> (a -> m r) -> m r -> m r) -> t m a foldrMx :: (IsStream t, Monad m) => (a -> m x -> m x) -> m x -> (m x -> m b) -> t m a -> m b -- | Like foldlx', but with a monadic step function. foldlMx' :: (IsStream t, Monad m) => (x -> a -> m x) -> m x -> (x -> m b) -> t m a -> m b -- | Strict left fold with an extraction function. Like the standard strict -- left fold, but applies a user supplied extraction function (the third -- argument) to the folded value at the end. This is designed to work -- with the foldl library. The suffix x is a mnemonic -- for extraction. foldlx' :: (IsStream t, Monad m) => (x -> a -> x) -> x -> (x -> b) -> t m a -> m b -- | Fold a stream by providing an SVar, a stop continuation, a singleton -- continuation and a yield continuation. The stream would share the -- current SVar passed via the State. foldStreamShared :: IsStream t => State StreamK m a -> (a -> t m a -> m r) -> (a -> m r) -> m r -> t m a -> m r -- | Fold a stream by providing a State, stop continuation, a singleton -- continuation and a yield continuation. The stream will not use the -- SVar passed via State. foldStream :: IsStream t => State StreamK m a -> (a -> t m a -> m r) -> (a -> m r) -> m r -> t m a -> m r -- | Fix the type of a polymorphic stream as SerialT. -- -- Since: 0.1.0 (Streamly) fromSerial :: IsStream t => SerialT m a -> t m a -- | Fix the type of a polymorphic stream as WSerialT. -- -- Since: 0.2.0 (Streamly) fromWSerial :: IsStream t => WSerialT m a -> t m a -- | Fix the type of a polymorphic stream as AsyncT. -- -- Since: 0.1.0 (Streamly) fromAsync :: IsStream t => AsyncT m a -> t m a -- | Fix the type of a polymorphic stream as WAsyncT. -- -- Since: 0.2.0 (Streamly) fromWAsync :: IsStream t => WAsyncT m a -> t m a -- | Fix the type of a polymorphic stream as AheadT. -- -- Since: 0.3.0 (Streamly) fromAhead :: IsStream t => AheadT m a -> t m a -- | Fix the type of a polymorphic stream as ParallelT. -- -- Since: 0.1.0 (Streamly) fromParallel :: IsStream t => ParallelT m a -> t m a -- | Fix the type of a polymorphic stream as ZipSerialM. -- -- Since: 0.2.0 (Streamly) fromZipSerial :: IsStream t => ZipSerialM m a -> t m a -- | Fix the type of a polymorphic stream as ZipAsyncM. -- -- Since: 0.2.0 (Streamly) fromZipAsync :: IsStream t => ZipAsyncM m a -> t m a -- | Construct a stream by adding a pure value at the head of an existing -- stream. For serial streams this is the same as (return a) `consM` -- r but more efficient. For concurrent streams this is not -- concurrent whereas consM is concurrent. For example: -- --
-- > toList $ 1 `cons` 2 `cons` 3 `cons` nil -- [1,2,3] --cons :: IsStream t => a -> t m a -> t m a infixr 5 `cons` -- | Operator equivalent of cons. -- --
-- > toList $ 1 .: 2 .: 3 .: nil -- [1,2,3] --(.:) :: IsStream t => a -> t m a -> t m a infixr 5 .: nil :: IsStream t => t m a nilM :: (IsStream t, Monad m) => m b -> t m a bindWith :: IsStream t => (t m b -> t m b -> t m b) -> t m a -> (a -> t m b) -> t m b -- | concatMapWith mixer generator stream is a two dimensional -- looping combinator. The generator function is used to -- generate streams from the elements in the input stream and -- the mixer function is used to merge those streams. -- -- Note we can merge streams concurrently by using a concurrent merge -- function. -- -- Since: 0.7.0 -- -- Since: 0.8.0 (signature change) concatMapWith :: IsStream t => (t m b -> t m b -> t m b) -> (a -> t m b) -> t m a -> t m b -- | A variant of foldMap that allows you to map a monadic -- streaming action on a Foldable container and then fold it using -- the specified stream merge operation. -- --
-- concatMapFoldableWith async return [1..3] ---- -- Equivalent to: -- --
-- concatMapFoldableWith f g = Prelude.foldr (f . g) S.nil -- concatMapFoldableWith f g xs = S.concatMapWith f g (S.fromFoldable xs) ---- -- Since: 0.8.0 (Renamed foldMapWith to concatMapFoldableWith) -- -- Since: 0.1.0 (Streamly) concatMapFoldableWith :: (IsStream t, Foldable f) => (t m b -> t m b -> t m b) -> (a -> t m b) -> f a -> t m b -- | Like concatMapFoldableWith but with the last two arguments -- reversed i.e. the monadic streaming function is the last argument. -- -- Equivalent to: -- --
-- concatForFoldableWith f xs g = Prelude.foldr (f . g) D.nil xs -- concatForFoldableWith f = flip (D.concatMapFoldableWith f) ---- -- Since: 0.8.0 (Renamed forEachWith to concatForFoldableWith) -- -- Since: 0.1.0 (Streamly) concatForFoldableWith :: (IsStream t, Foldable f) => (t m b -> t m b -> t m b) -> f a -> (a -> t m b) -> t m b -- | A variant of fold that allows you to fold a Foldable -- container of streams using the specified stream sum operation. -- --
-- concatFoldableWith async $ map return [1..3] ---- -- Equivalent to: -- --
-- concatFoldableWith f = Prelude.foldr f D.nil -- concatFoldableWith f = D.concatMapFoldableWith f id ---- -- Since: 0.8.0 (Renamed foldWith to concatFoldableWith) -- -- Since: 0.1.0 (Streamly) concatFoldableWith :: (IsStream t, Foldable f) => (t m a -> t m a -> t m a) -> f (t m a) -> t m a nil :: IsStream t => t m a nilM :: (IsStream t, Monad m) => m b -> t m a -- | Construct a stream by adding a pure value at the head of an existing -- stream. For serial streams this is the same as (return a) `consM` -- r but more efficient. For concurrent streams this is not -- concurrent whereas consM is concurrent. For example: -- --
-- > toList $ 1 `cons` 2 `cons` 3 `cons` nil -- [1,2,3] --cons :: IsStream t => a -> t m a -> t m a infixr 5 `cons` -- | Operator equivalent of cons. -- --
-- > toList $ 1 .: 2 .: 3 .: nil -- [1,2,3] --(.:) :: IsStream t => a -> t m a -> t m a infixr 5 .: -- | Constructs a stream by adding a monadic action at the head of an -- existing stream. For example: -- --
-- > toList $ getLine `consM` getLine `consM` nil -- hello -- world -- ["hello","world"] ---- -- Concurrent (do not use fromParallel to construct infinite -- streams) consM :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a infixr 5 `consM` -- | Operator equivalent of consM. We can read it as "parallel -- colon" to remember that | comes before :. -- --
-- > toList $ getLine |: getLine |: nil -- hello -- world -- ["hello","world"] ---- --
-- let delay = threadDelay 1000000 >> print 1 -- drain $ fromSerial $ delay |: delay |: delay |: nil -- drain $ fromParallel $ delay |: delay |: delay |: nil ---- -- Concurrent (do not use fromParallel to construct infinite -- streams) (|:) :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a infixr 5 |: -- | Convert an Unfold into a stream by supplying it an input seed. -- --
-- >>> Stream.drain $ Stream.unfold Unfold.replicateM (3, putStrLn "hello") -- hello -- hello -- hello ---- -- Since: 0.7.0 unfold :: (IsStream t, Monad m) => Unfold m a b -> a -> t m b -- | Convert an Unfold with a closed input end into a stream. -- -- Pre-release unfold0 :: (IsStream t, Monad m) => Unfold m Void b -> t m b -- |
-- >>> :{ -- unfoldr step s = -- case step s of -- Nothing -> Stream.nil -- Just (a, b) -> a `Stream.cons` unfoldr step b -- :} ---- -- Build a stream by unfolding a pure step function step -- starting from a seed s. The step function returns the next -- element in the stream and the next seed value. When it is done it -- returns Nothing and the stream ends. For example, -- --
-- >>> :{ -- let f b = -- if b > 2 -- then Nothing -- else Just (b, b + 1) -- in Stream.toList $ Stream.unfoldr f 0 -- :} -- [0,1,2] --unfoldr :: (Monad m, IsStream t) => (b -> Maybe (a, b)) -> b -> t m a -- | Build a stream by unfolding a monadic step function starting -- from a seed. The step function returns the next element in the stream -- and the next seed value. When it is done it returns Nothing and -- the stream ends. For example, -- --
-- >>> :{ -- let f b = -- if b > 2 -- then return Nothing -- else return (Just (b, b + 1)) -- in Stream.toList $ Stream.unfoldrM f 0 -- :} -- [0,1,2] ---- -- When run concurrently, the next unfold step can run concurrently with -- the processing of the output of the previous step. Note that more than -- one step cannot run concurrently as the next step depends on the -- output of the previous step. -- --
-- >>> :{ -- let f b = -- if b > 2 -- then return Nothing -- else threadDelay 1000000 >> return (Just (b, b + 1)) -- in Stream.toList $ Stream.delay 1 $ Stream.fromAsync $ Stream.unfoldrM f 0 -- :} -- [0,1,2] ---- -- Concurrent -- -- Since: 0.1.0 unfoldrM :: forall t m b a. (IsStream t, MonadAsync m) => (b -> m (Maybe (a, b))) -> b -> t m a -- |
-- fromPure a = a `cons` nil ---- -- Create a singleton stream from a pure value. -- -- The following holds in monadic streams, but not in Zip streams: -- --
-- fromPure = pure -- fromPure = fromEffect . pure ---- -- In Zip applicative streams fromPure is not the same as -- pure because in that case pure is equivalent to -- repeat instead. fromPure and pure are equally -- efficient, in other cases fromPure may be slightly more -- efficient than the other equivalent definitions. -- -- Since: 0.8.0 (Renamed yield to fromPure) fromPure :: IsStream t => a -> t m a -- |
-- fromEffect m = m `consM` nil ---- -- Create a singleton stream from a monadic action. -- --
-- > Stream.toList $ Stream.fromEffect getLine -- hello -- ["hello"] ---- -- Since: 0.8.0 (Renamed yieldM to fromEffect) fromEffect :: (Monad m, IsStream t) => m a -> t m a -- | Generate an infinite stream by repeating a pure value. repeat :: (IsStream t, Monad m) => a -> t m a -- |
-- >>> repeatM = fix . consM -- -- >>> repeatM = cycle1 . fromEffect ---- -- Generate a stream by repeatedly executing a monadic action forever. -- --
-- >>> :{ -- repeatAsync = -- Stream.repeatM (threadDelay 1000000 >> print 1) -- & Stream.take 10 -- & Stream.fromAsync -- & Stream.drain -- :} ---- -- Concurrent, infinite (do not use with fromParallel) repeatM :: (IsStream t, MonadAsync m) => m a -> t m a -- |
-- >>> replicate n = Stream.take n . Stream.repeat ---- -- Generate a stream of length n by repeating a value n -- times. replicate :: (IsStream t, Monad m) => Int -> a -> t m a -- |
-- >>> replicateM n = Stream.take n . Stream.repeatM ---- -- Generate a stream by performing a monadic action n times. -- Same as: -- --
-- >>> pr n = threadDelay 1000000 >> print n ---- -- This runs serially and takes 3 seconds: -- --
-- >>> Stream.drain $ Stream.fromSerial $ Stream.replicateM 3 $ pr 1 -- 1 -- 1 -- 1 ---- -- This runs concurrently and takes just 1 second: -- --
-- >>> Stream.drain $ Stream.fromAsync $ Stream.replicateM 3 $ pr 1 -- 1 -- 1 -- 1 ---- -- Concurrent replicateM :: forall t m a. (IsStream t, MonadAsync m) => Int -> m a -> t m a -- | Types that can be enumerated as a stream. The operations in this type -- class are equivalent to those in the Enum type class, except -- that these generate a stream instead of a list. Use the functions in -- Streamly.Internal.Data.Stream.Enumeration module to define new -- instances. class Enum a => Enumerable a -- | enumerateFrom from generates a stream starting with the -- element from, enumerating up to maxBound when the type -- is Bounded or generating an infinite stream when the type is -- not Bounded. -- --
-- >>> Stream.toList $ Stream.take 4 $ Stream.enumerateFrom (0 :: Int) -- [0,1,2,3] ---- -- For Fractional types, enumeration is numerically stable. -- However, no overflow or underflow checks are performed. -- --
-- >>> Stream.toList $ Stream.take 4 $ Stream.enumerateFrom 1.1 -- [1.1,2.1,3.1,4.1] --enumerateFrom :: (Enumerable a, IsStream t, Monad m) => a -> t m a -- | Generate a finite stream starting with the element from, -- enumerating the type up to the value to. If to is -- smaller than from then an empty stream is returned. -- --
-- >>> Stream.toList $ Stream.enumerateFromTo 0 4 -- [0,1,2,3,4] ---- -- For Fractional types, the last element is equal to the -- specified to value after rounding to the nearest integral -- value. -- --
-- >>> Stream.toList $ Stream.enumerateFromTo 1.1 4 -- [1.1,2.1,3.1,4.1] -- -- >>> Stream.toList $ Stream.enumerateFromTo 1.1 4.6 -- [1.1,2.1,3.1,4.1,5.1] --enumerateFromTo :: (Enumerable a, IsStream t, Monad m) => a -> a -> t m a -- | enumerateFromThen from then generates a stream whose first -- element is from, the second element is then and the -- successive elements are in increments of then - from. -- Enumeration can occur downwards or upwards depending on whether -- then comes before or after from. For Bounded -- types the stream ends when maxBound is reached, for unbounded -- types it keeps enumerating infinitely. -- --
-- >>> Stream.toList $ Stream.take 4 $ Stream.enumerateFromThen 0 2 -- [0,2,4,6] -- -- >>> Stream.toList $ Stream.take 4 $ Stream.enumerateFromThen 0 (-2) -- [0,-2,-4,-6] --enumerateFromThen :: (Enumerable a, IsStream t, Monad m) => a -> a -> t m a -- | enumerateFromThenTo from then to generates a finite stream -- whose first element is from, the second element is -- then and the successive elements are in increments of -- then - from up to to. Enumeration can occur -- downwards or upwards depending on whether then comes before -- or after from. -- --
-- >>> Stream.toList $ Stream.enumerateFromThenTo 0 2 6 -- [0,2,4,6] -- -- >>> Stream.toList $ Stream.enumerateFromThenTo 0 (-2) (-6) -- [0,-2,-4,-6] --enumerateFromThenTo :: (Enumerable a, IsStream t, Monad m) => a -> a -> a -> t m a -- |
-- enumerate = enumerateFrom minBound ---- -- Enumerate a Bounded type from its minBound to -- maxBound enumerate :: (IsStream t, Monad m, Bounded a, Enumerable a) => t m a -- |
-- enumerateTo = enumerateFromTo minBound ---- -- Enumerate a Bounded type from its minBound to specified -- value. enumerateTo :: (IsStream t, Monad m, Bounded a, Enumerable a) => a -> t m a -- | times returns a stream of time value tuples with clock of 10 -- ms granularity. The first component of the tuple is an absolute time -- reference (epoch) denoting the start of the stream and the second -- component is a time relative to the reference. -- --
-- >>> Stream.mapM_ (\x -> print x >> threadDelay 1000000) $ Stream.take 3 $ Stream.times -- (AbsTime (TimeSpec {sec = ..., nsec = ...}),RelTime64 (NanoSecond64 ...)) -- (AbsTime (TimeSpec {sec = ..., nsec = ...}),RelTime64 (NanoSecond64 ...)) -- (AbsTime (TimeSpec {sec = ..., nsec = ...}),RelTime64 (NanoSecond64 ...)) ---- -- Note: This API is not safe on 32-bit machines. -- -- Pre-release times :: (IsStream t, MonadAsync m) => t m (AbsTime, RelTime64) -- | absTimes returns a stream of absolute timestamps using a -- clock of 10 ms granularity. -- --
-- >>> Stream.mapM_ print $ Stream.delayPre 1 $ Stream.take 3 $ Stream.absTimes -- AbsTime (TimeSpec {sec = ..., nsec = ...}) -- AbsTime (TimeSpec {sec = ..., nsec = ...}) -- AbsTime (TimeSpec {sec = ..., nsec = ...}) ---- -- Note: This API is not safe on 32-bit machines. -- -- Pre-release absTimes :: (IsStream t, MonadAsync m, Functor (t m)) => t m AbsTime -- | absTimesWith g returns a stream of absolute timestamps using -- a clock of granularity g specified in seconds. A low -- granularity clock is more expensive in terms of CPU usage. Any -- granularity lower than 1 ms is treated as 1 ms. -- --
-- >>> Stream.mapM_ print $ Stream.delayPre 1 $ Stream.take 3 $ absTimesWith 0.01 -- AbsTime (TimeSpec {sec = ..., nsec = ...}) -- AbsTime (TimeSpec {sec = ..., nsec = ...}) -- AbsTime (TimeSpec {sec = ..., nsec = ...}) ---- -- Note: This API is not safe on 32-bit machines. -- -- Pre-release absTimesWith :: (IsStream t, MonadAsync m, Functor (t m)) => Double -> t m AbsTime -- | relTimes returns a stream of relative time values starting -- from 0, using a clock of granularity 10 ms. -- --
-- >>> Stream.mapM_ print $ Stream.delayPre 1 $ Stream.take 3 $ Stream.relTimes -- RelTime64 (NanoSecond64 ...) -- RelTime64 (NanoSecond64 ...) -- RelTime64 (NanoSecond64 ...) ---- -- Note: This API is not safe on 32-bit machines. -- -- Pre-release relTimes :: (IsStream t, MonadAsync m, Functor (t m)) => t m RelTime64 -- | relTimesWith g returns a stream of relative time values -- starting from 0, using a clock of granularity g specified in -- seconds. A low granularity clock is more expensive in terms of CPU -- usage. Any granularity lower than 1 ms is treated as 1 ms. -- --
-- >>> Stream.mapM_ print $ Stream.delayPre 1 $ Stream.take 3 $ Stream.relTimesWith 0.01 -- RelTime64 (NanoSecond64 ...) -- RelTime64 (NanoSecond64 ...) -- RelTime64 (NanoSecond64 ...) ---- -- Note: This API is not safe on 32-bit machines. -- -- Pre-release relTimesWith :: (IsStream t, MonadAsync m, Functor (t m)) => Double -> t m RelTime64 -- | durations g returns a stream of relative time values -- measuring the time elapsed since the immediate predecessor element of -- the stream was generated. The first element of the stream is always 0. -- durations uses a clock of granularity g specified in -- seconds. A low granularity clock is more expensive in terms of CPU -- usage. The minimum granularity is 1 millisecond. Durations lower than -- 1 ms will be 0. -- -- Note: This API is not safe on 32-bit machines. -- -- Unimplemented durations :: Double -> t m RelTime64 -- | Generate ticks at the specified rate. The rate is adaptive, the tick -- generation speed can be increased or decreased at different times to -- achieve the specified rate. The specific behavior for different styles -- of Rate specifications is documented under Rate. The -- effective maximum rate achieved by a stream is governed by the -- processor speed. -- -- Unimplemented ticks :: Rate -> t m () -- | Generate a singleton event at or after the specified absolute time. -- Note that this is different from a threadDelay, a threadDelay starts -- from the time when the action is evaluated, whereas if we use AbsTime -- based timeout it will immediately expire if the action is evaluated -- too late. -- -- Unimplemented timeout :: AbsTime -> t m () -- |
-- >>> fromIndices f = fmap f $ Stream.enumerateFrom 0 -- -- >>> fromIndices f = let g i = f i `Stream.cons` g (i + 1) in g 0 ---- -- Generate an infinite stream, whose values are the output of a function -- f applied on the corresponding index. Index starts at 0. -- --
-- >>> Stream.toList $ Stream.take 5 $ Stream.fromIndices id -- [0,1,2,3,4] --fromIndices :: (IsStream t, Monad m) => (Int -> a) -> t m a -- |
-- >>> fromIndicesM f = Stream.mapM f $ Stream.enumerateFrom 0 -- -- >>> fromIndicesM f = let g i = f i `Stream.consM` g (i + 1) in g 0 ---- -- Generate an infinite stream, whose values are the output of a monadic -- function f applied on the corresponding index. Index starts -- at 0. -- -- Concurrent fromIndicesM :: forall t m a. (IsStream t, MonadAsync m) => (Int -> m a) -> t m a -- |
-- >>> iterate f x = x `Stream.cons` iterate f x ---- -- Generate an infinite stream with x as the first element and -- each successive element derived by applying the function f on -- the previous element. -- --
-- >>> Stream.toList $ Stream.take 5 $ Stream.iterate (+1) 1 -- [1,2,3,4,5] --iterate :: (IsStream t, Monad m) => (a -> a) -> a -> t m a -- |
-- >>> iterateM f m = m >>= \a -> return a `Stream.consM` iterateM f (f a) ---- -- Generate an infinite stream with the first element generated by the -- action m and each successive element derived by applying the -- monadic function f on the previous element. -- --
-- >>> pr n = threadDelay 1000000 >> print n -- -- >>> :{ -- Stream.iterateM (\x -> pr x >> return (x + 1)) (return 0) -- & Stream.take 3 -- & Stream.fromSerial -- & Stream.toList -- :} -- 0 -- 1 -- [0,1,2] ---- -- When run concurrently, the next iteration can run concurrently with -- the processing of the previous iteration. Note that more than one -- iteration cannot run concurrently as the next iteration depends on the -- output of the previous iteration. -- --
-- >>> :{ -- Stream.iterateM (\x -> pr x >> return (x + 1)) (return 0) -- & Stream.delay 1 -- & Stream.take 3 -- & Stream.fromAsync -- & Stream.toList -- :} -- 0 -- 1 -- ... ---- -- Concurrent -- -- Since: 0.1.2 -- -- Since: 0.7.0 (signature change) iterateM :: forall t m a. (IsStream t, MonadAsync m) => (a -> m a) -> m a -> t m a -- | We can define cyclic structures using let: -- --
-- >>> let (a, b) = ([1, b], head a) in (a, b) -- ([1,1],1) ---- -- The function fix defined as: -- --
-- >>> fix f = let x = f x in x ---- -- ensures that the argument of a function and its output refer to the -- same lazy value x i.e. the same location in memory. Thus -- x can be defined in terms of itself, creating structures with -- cyclic references. -- --
-- >>> f ~(a, b) = ([1, b], head a) -- -- >>> fix f -- ([1,1],1) ---- -- mfix is essentially the same as fix but for monadic -- values. -- -- Using mfix for streams we can construct a stream in which each -- element of the stream is defined in a cyclic fashion. The argument of -- the function being fixed represents the current element of the stream -- which is being returned by the stream monad. Thus, we can use the -- argument to construct itself. -- -- Pre-release mfix :: (IsStream t, Monad m) => (m a -> t m a) -> t m a -- |
-- fromList = foldr cons nil ---- -- Construct a stream from a list of pure values. This is more efficient -- than fromFoldable for serial streams. fromList :: (Monad m, IsStream t) => [a] -> t m a -- |
-- >>> fromListM = Stream.fromFoldableM -- -- >>> fromListM = Stream.sequence . Stream.fromList -- -- >>> fromListM = Stream.mapM id . Stream.fromList -- -- >>> fromListM = Prelude.foldr Stream.consM Stream.nil ---- -- Construct a stream from a list of monadic actions. This is more -- efficient than fromFoldableM for serial streams. fromListM :: (MonadAsync m, IsStream t) => [m a] -> t m a -- |
-- >>> fromFoldable = Prelude.foldr Stream.cons Stream.nil ---- -- Construct a stream from a Foldable containing pure values: fromFoldable :: (IsStream t, Foldable f) => f a -> t m a -- |
-- >>> fromFoldableM = Prelude.foldr Stream.consM Stream.nil ---- -- Construct a stream from a Foldable containing monadic actions. -- --
-- >>> pr n = threadDelay 1000000 >> print n -- -- >>> Stream.drain $ Stream.fromSerial $ Stream.fromFoldableM $ map pr [1,2,3] -- 1 -- 2 -- 3 ---- --
-- >>> Stream.drain $ Stream.fromAsync $ Stream.fromFoldableM $ map pr [1,2,3] -- ... -- ... -- ... ---- -- Concurrent (do not use with fromParallel on infinite -- containers) fromFoldableM :: (IsStream t, MonadAsync m, Foldable f) => f (m a) -> t m a -- | Takes a callback setter function and provides it with a callback. The -- callback when invoked adds a value at the tail of the stream. Returns -- a stream of values generated by the callback. -- -- Pre-release fromCallback :: MonadAsync m => ((a -> m ()) -> m ()) -> SerialT m a -- | Construct a stream by reading an Unboxed IORef -- repeatedly. -- -- Pre-release fromPrimIORef :: (IsStream t, MonadIO m, Unbox a) => IORef a -> t m a -- | Same as fromPure yield :: IsStream t => a -> t m a -- | Same as fromEffect yieldM :: (Monad m, IsStream t) => m a -> t m a -- | Read lines from an IO Handle into a stream of Strings. fromHandle :: (IsStream t, MonadIO m) => Handle -> t m String currentTime :: (IsStream t, MonadAsync m, Functor (t m)) => Double -> t m AbsTime -- | Fold a stream using the supplied left Fold and reducing the -- resulting expression strictly at each step. The behavior is similar to -- foldl'. A Fold can terminate early without consuming -- the full stream. See the documentation of individual Folds for -- termination behavior. -- --
-- >>> Stream.fold Fold.sum (Stream.enumerateFromTo 1 100) -- 5050 ---- -- Folds never fail, therefore, they produce a default value even when no -- input is provided. It means we can always fold an empty stream and get -- a valid result. For example: -- --
-- >>> Stream.fold Fold.sum Stream.nil -- 0 ---- -- However, foldMany on an empty stream results in an empty -- stream. Therefore, Stream.fold f is not the same as -- Stream.head . Stream.foldMany f. -- --
-- fold f = Stream.parse (Parser.fromFold f) --fold :: Monad m => Fold m a b -> SerialT m a -> m b -- | Decompose a stream into its head and tail. If the stream is empty, -- returns Nothing. If the stream is non-empty, returns Just -- (a, ma), where a is the head of the stream and -- ma its tail. -- -- This can be used to do pretty much anything in an imperative manner, -- as it just breaks down the stream into individual elements and we can -- loop over them as we deem fit. For example, this can be used to -- convert a streamly stream into other stream types. -- -- All the folds in this module can be expressed in terms of -- uncons, however, this is generally less efficient than specific -- folds because it takes apart the stream one element at a time, -- therefore, does not take adavantage of stream fusion. uncons :: (IsStream t, Monad m) => SerialT m a -> m (Maybe (a, t m a)) -- | Right associative/lazy pull fold. foldrM build final stream -- constructs an output structure using the step function build. -- build is invoked with the next input element and the -- remaining (lazy) tail of the output structure. It builds a lazy output -- expression using the two. When the "tail structure" in the output -- expression is evaluated it calls build again thus lazily -- consuming the input stream until either the output expression -- built by build is free of the "tail" or the input is -- exhausted in which case final is used as the terminating case -- for the output structure. For more details see the description in the -- previous section. -- -- Example, determine if any element is odd in a stream: -- --
-- >>> Stream.foldrM (\x xs -> if odd x then return True else xs) (return False) $ Stream.fromList (2:4:5:undefined) -- True ---- -- Since: 0.7.0 (signature changed) -- -- Since: 0.2.0 (signature changed) -- -- Since: 0.1.0 foldrM :: Monad m => (a -> m b -> m b) -> m b -> SerialT m a -> m b -- | Right fold, lazy for lazy monads and pure streams, and strict for -- strict monads. -- -- Please avoid using this routine in strict monads like IO unless you -- need a strict right fold. This is provided only for use in lazy monads -- (e.g. Identity) or pure streams. Note that with this signature it is -- not possible to implement a lazy foldr when the monad m is -- strict. In that case it would be strict in its accumulator and -- therefore would necessarily consume all its input. foldr :: Monad m => (a -> b -> b) -> b -> SerialT m a -> m b -- | Lazy right fold for non-empty streams, using first element as the -- starting value. Returns Nothing if the stream is empty. foldr1 :: Monad m => (a -> a -> a) -> SerialT m a -> m (Maybe a) -- | Lazy left fold to a stream. foldlS :: IsStream t => (t m b -> a -> t m b) -> t m b -> t m a -> t m b -- | Lazy left fold to a transformer monad. -- -- For example, to reverse a stream: -- --
-- D.toList $ D.foldlT (flip D.cons) D.nil $ (D.fromList [1..5] :: SerialT IO Int) --foldlT :: (Monad m, IsStream t, Monad (s m), MonadTrans s) => (s m b -> a -> s m b) -> s m b -> t m a -> s m b -- | Strict left fold with an extraction function. Like the standard strict -- left fold, but applies a user supplied extraction function (the third -- argument) to the folded value at the end. This is designed to work -- with the foldl library. The suffix x is a mnemonic -- for extraction. foldx :: Monad m => (x -> a -> x) -> x -> (x -> b) -> SerialT m a -> m b -- | Left associative/strict push fold. foldl' reduce initial -- stream invokes reduce with the accumulator and the next -- input in the input stream, using initial as the initial value -- of the current value of the accumulator. When the input is exhausted -- the current value of the accumulator is returned. Make sure to use a -- strict data structure for accumulator to not build unnecessary lazy -- expressions unless that's what you want. See the previous section for -- more details. foldl' :: Monad m => (b -> a -> b) -> b -> SerialT m a -> m b -- | Strict left fold, for non-empty streams, using first element as the -- starting value. Returns Nothing if the stream is empty. foldl1' :: Monad m => (a -> a -> a) -> SerialT m a -> m (Maybe a) -- | Like foldx, but with a monadic step function. foldxM :: Monad m => (x -> a -> m x) -> m x -> (x -> m b) -> SerialT m a -> m b -- | Like foldl' but with a monadic step function. -- -- Since: 0.2.0 -- -- Since: 0.8.0 (signature change) foldlM' :: Monad m => (b -> a -> m b) -> m b -> SerialT m a -> m b -- | Parse a stream using the supplied ParserD Parser. -- -- Internal parseD :: Monad m => Parser a m b -> SerialT m a -> m (Either ParseError b) -- | Parse a stream using the supplied Parser. -- -- Unlike folds, parsers may not always result in a valid output, they -- may result in an error. For example: -- --
-- >>> Stream.parse (Parser.takeEQ 1 Fold.drain) Stream.nil -- Left (ParseError "takeEQ: Expecting exactly 1 elements, input terminated on 0") ---- -- Note: -- --
-- fold f = Stream.parse (Parser.fromFold f) ---- -- parse p is not the same as head . parseMany p on an -- empty stream. -- -- Pre-release parse :: Monad m => Parser a m b -> SerialT m a -> m (Either ParseError b) -- |
-- mapM_ = Stream.drain . Stream.mapM ---- -- Apply a monadic action to each element of the stream and discard the -- output of the action. This is not really a pure transformation -- operation but a transformation followed by fold. mapM_ :: Monad m => (a -> m b) -> SerialT m a -> m () -- |
-- drain = mapM_ (\_ -> return ()) -- drain = Stream.fold Fold.drain ---- -- Run a stream, discarding the results. By default it interprets the -- stream as SerialT, to run other types of streams use the type -- adapting combinators for example Stream.drain . -- fromAsync. drain :: Monad m => SerialT m a -> m () -- |
-- drainN n = Stream.drain . Stream.take n -- drainN n = Stream.fold (Fold.take n Fold.drain) ---- -- Run maximum up to n iterations of a stream. drainN :: Monad m => Int -> SerialT m a -> m () -- |
-- runN n = runStream . take n ---- -- Run maximum up to n iterations of a stream. runN :: Monad m => Int -> SerialT m a -> m () -- |
-- drainWhile p = Stream.drain . Stream.takeWhile p ---- -- Run a stream as long as the predicate holds true. drainWhile :: Monad m => (a -> Bool) -> SerialT m a -> m () -- |
-- runWhile p = runStream . takeWhile p ---- -- Run a stream as long as the predicate holds true. runWhile :: Monad m => (a -> Bool) -> SerialT m a -> m () -- | Run a stream, discarding the results. By default it interprets the -- stream as SerialT, to run other types of streams use the type -- adapting combinators for example runStream . -- fromAsync. runStream :: Monad m => SerialT m a -> m () -- | Determine whether the stream is empty. -- --
-- null = Stream.fold Fold.null --null :: Monad m => SerialT m a -> m Bool -- | Extract the first element of the stream, if any. -- --
-- head = (!! 0) -- head = Stream.fold Fold.one --head :: Monad m => SerialT m a -> m (Maybe a) -- | Extract the first element of the stream, if any, otherwise use the -- supplied default value. It can help avoid one branch in high -- performance code. -- -- Pre-release headElse :: Monad m => a -> SerialT m a -> m a -- |
-- tail = fmap (fmap snd) . Stream.uncons ---- -- Extract all but the first element of the stream, if any. tail :: (IsStream t, Monad m) => SerialT m a -> m (Maybe (t m a)) -- | Extract all but the last element of the stream, if any. init :: (IsStream t, Monad m) => SerialT m a -> m (Maybe (t m a)) -- | Extract the last element of the stream, if any. -- --
-- last xs = xs !! (Stream.length xs - 1) -- last = Stream.fold Fold.last --last :: Monad m => SerialT m a -> m (Maybe a) -- | Determine whether an element is present in the stream. -- --
-- elem = Stream.fold Fold.elem --elem :: (Monad m, Eq a) => a -> SerialT m a -> m Bool -- | Determine whether an element is not present in the stream. -- --
-- notElem = Stream.fold Fold.length --notElem :: (Monad m, Eq a) => a -> SerialT m a -> m Bool -- | Determine the length of the stream. length :: Monad m => SerialT m a -> m Int -- | Determine whether all elements of a stream satisfy a predicate. -- --
-- all = Stream.fold Fold.all --all :: Monad m => (a -> Bool) -> SerialT m a -> m Bool -- | Determine whether any of the elements of a stream satisfy a predicate. -- --
-- any = Stream.fold Fold.any --any :: Monad m => (a -> Bool) -> SerialT m a -> m Bool -- | Determines if all elements of a boolean stream are True. -- --
-- and = Stream.fold Fold.and --and :: Monad m => SerialT m Bool -> m Bool -- | Determines whether at least one element of a boolean stream is True. -- --
-- or = Stream.fold Fold.or --or :: Monad m => SerialT m Bool -> m Bool -- | Determine the sum of all elements of a stream of numbers. Returns -- 0 when the stream is empty. Note that this is not numerically -- stable for floating point numbers. -- --
-- sum = Stream.fold Fold.sum --sum :: (Monad m, Num a) => SerialT m a -> m a -- | Determine the product of all elements of a stream of numbers. Returns -- 1 when the stream is empty. -- --
-- product = Stream.fold Fold.product --product :: (Monad m, Num a) => SerialT m a -> m a -- | Fold a stream of monoid elements by appending them. -- --
-- mconcat = Stream.fold Fold.mconcat ---- -- Pre-release mconcat :: (Monad m, Monoid a) => SerialT m a -> m a -- |
-- minimum = minimumBy compare -- minimum = Stream.fold Fold.minimum ---- -- Determine the minimum element in a stream. minimum :: (Monad m, Ord a) => SerialT m a -> m (Maybe a) -- | Determine the minimum element in a stream using the supplied -- comparison function. -- --
-- minimumBy = Stream.fold Fold.minimumBy --minimumBy :: Monad m => (a -> a -> Ordering) -> SerialT m a -> m (Maybe a) -- |
-- maximum = maximumBy compare -- maximum = Stream.fold Fold.maximum ---- -- Determine the maximum element in a stream. maximum :: (Monad m, Ord a) => SerialT m a -> m (Maybe a) -- | Determine the maximum element in a stream using the supplied -- comparison function. -- --
-- maximumBy = Stream.fold Fold.maximumBy --maximumBy :: Monad m => (a -> a -> Ordering) -> SerialT m a -> m (Maybe a) -- | Ensures that all the elements of the stream are identical and then -- returns that unique element. the :: (Eq a, Monad m) => SerialT m a -> m (Maybe a) -- | Lookup the element at the given index. (!!) :: Monad m => SerialT m a -> Int -> m (Maybe a) -- | In a stream of (key-value) pairs (a, b), return the value -- b of the first pair where the key equals the given value -- a. -- --
-- lookup = snd <$> Stream.find ((==) . fst) -- lookup = Stream.fold Fold.lookup --lookup :: (Monad m, Eq a) => a -> SerialT m (a, b) -> m (Maybe b) -- | Like findM but with a non-monadic predicate. -- --
-- find p = findM (return . p) -- find = Stream.fold Fold.find --find :: Monad m => (a -> Bool) -> SerialT m a -> m (Maybe a) -- | Returns the first element that satisfies the given predicate. -- --
-- findM = Stream.fold Fold.findM --findM :: Monad m => (a -> m Bool) -> SerialT m a -> m (Maybe a) -- | Returns the first index that satisfies the given predicate. -- --
-- findIndex = Stream.fold Fold.findIndex --findIndex :: Monad m => (a -> Bool) -> SerialT m a -> m (Maybe Int) -- | Returns the first index where a given value is found in the stream. -- --
-- elemIndex a = Stream.findIndex (== a) --elemIndex :: (Monad m, Eq a) => a -> SerialT m a -> m (Maybe Int) -- |
-- toList = Stream.foldr (:) [] ---- -- Convert a stream into a list in the underlying monad. The list can be -- consumed lazily in a lazy monad (e.g. Identity). In a strict -- monad (e.g. IO) the whole list is generated and buffered before it can -- be consumed. -- -- Warning! working on large lists accumulated as buffers in -- memory could be very inefficient, consider using Streamly.Array -- instead. toList :: Monad m => SerialT m a -> m [a] -- |
-- toListRev = Stream.foldl' (flip (:)) [] ---- -- Convert a stream into a list in reverse order in the underlying monad. -- -- Warning! working on large lists accumulated as buffers in -- memory could be very inefficient, consider using Streamly.Array -- instead. -- -- Pre-release toListRev :: Monad m => SerialT m a -> m [a] -- |
-- toHandle h = D.mapM_ $ hPutStrLn h ---- -- Write a stream of Strings to an IO Handle. toHandle :: MonadIO m => Handle -> SerialT m String -> m () -- | Convert a stream to a pure stream in reverse order. -- --
-- toStreamRev = Stream.foldl' (flip Stream.cons) Stream.nil ---- -- Pre-release toStreamRev :: Monad m => SerialT m a -> m (SerialT n a) -- | Parallel fold application operator; applies a fold function t m a -- -> m b to a stream t m a concurrently; The the input -- stream is evaluated asynchronously in an independent thread yielding -- elements to a buffer and the folding action runs in another thread -- consuming the input from the buffer. -- -- If you read the signature as (t m a -> m b) -> (t m a -> -- m b) you can look at it as a transformation that converts a fold -- function to a buffered concurrent fold function. -- -- The . at the end of the operator is a mnemonic for -- termination of the stream. -- -- In the example below, each stage introduces a delay of 1 sec but -- output is printed every second because both stages are concurrent. -- --
-- >>> import Control.Concurrent (threadDelay) -- -- >>> import Streamly.Prelude ((|$.)) -- -- >>> :{ -- Stream.foldlM' (\_ a -> threadDelay 1000000 >> print a) (return ()) -- |$. Stream.replicateM 3 (threadDelay 1000000 >> return 1) -- :} -- 1 -- 1 -- 1 ---- -- Concurrent -- -- Since: 0.3.0 (Streamly) (|$.) :: (IsStream t, MonadAsync m) => (t m a -> m b) -> t m a -> m b infixr 0 |$. -- | Same as |$.. -- -- Internal foldAsync :: (IsStream t, MonadAsync m) => (t m a -> m b) -> t m a -> m b -- | Same as |$. but with arguments reversed. -- --
-- (|&.) = flip (|$.) ---- -- Concurrent -- -- Since: 0.3.0 (Streamly) (|&.) :: (IsStream t, MonadAsync m) => t m a -> (t m a -> m b) -> m b infixl 1 |&. -- | Returns True if the first stream is the same as or a prefix of -- the second. A stream is a prefix of itself. -- --
-- >>> Stream.isPrefixOf (Stream.fromList "hello") (Stream.fromList "hello" :: SerialT IO Char) -- True --isPrefixOf :: (Eq a, IsStream t, Monad m) => t m a -> t m a -> m Bool -- | Returns True if the first stream is an infix of the second. A -- stream is considered an infix of itself. -- --
-- Stream.isInfixOf (Stream.fromList "hello") (Stream.fromList "hello" :: SerialT IO Char) ---- -- True -- -- Space: O(n) worst case where n is the length of the -- infix. -- -- Pre-release -- -- Requires Storable constraint isInfixOf :: (MonadIO m, Eq a, Enum a, Storable a, Unbox a) => SerialT m a -> SerialT m a -> m Bool -- | Returns True if the first stream is a suffix of the second. A -- stream is considered a suffix of itself. -- --
-- >>> Stream.isSuffixOf (Stream.fromList "hello") (Stream.fromList "hello" :: SerialT IO Char) -- True ---- -- Space: O(n), buffers entire input stream and the suffix. -- -- Pre-release -- -- Suboptimal - Help wanted. isSuffixOf :: (Monad m, Eq a) => SerialT m a -> SerialT m a -> m Bool -- | Returns True if all the elements of the first stream occur, in -- order, in the second stream. The elements do not have to occur -- consecutively. A stream is a subsequence of itself. -- --
-- >>> Stream.isSubsequenceOf (Stream.fromList "hlo") (Stream.fromList "hello" :: SerialT IO Char) -- True --isSubsequenceOf :: (Eq a, IsStream t, Monad m) => t m a -> t m a -> m Bool -- | stripPrefix prefix stream strips prefix from -- stream if it is a prefix of stream. Returns Nothing if -- the stream does not start with the given prefix, stripped stream -- otherwise. Returns Just nil when the prefix is the same as -- the stream. -- -- See also "Streamly.Internal.Data.Stream.IsStream.Nesting.dropPrefix". -- -- Space: O(1) stripPrefix :: (Eq a, IsStream t, Monad m) => t m a -> t m a -> m (Maybe (t m a)) -- | Drops the given suffix from a stream. Returns Nothing if the -- stream does not end with the given suffix. Returns Just nil -- when the suffix is the same as the stream. -- -- It may be more efficient to convert the stream to an Array and use -- stripSuffix on that especially if the elements have a Storable or Prim -- instance. -- -- See also "Streamly.Internal.Data.Stream.IsStream.Nesting.dropSuffix". -- -- Space: O(n), buffers the entire input stream as well as the -- suffix -- -- Pre-release stripSuffix :: (Monad m, Eq a) => SerialT m a -> SerialT m a -> m (Maybe (SerialT m a)) -- | Compare two streams for equality using an equality function. eqBy :: (IsStream t, Monad m) => (a -> b -> Bool) -> t m a -> t m b -> m Bool -- | Compare two streams lexicographically using a comparison function. cmpBy :: (IsStream t, Monad m) => (a -> b -> Ordering) -> t m a -> t m b -> m Ordering -- | Use a Pipe to transform a stream. -- -- Pre-release transform :: (IsStream t, Monad m) => Pipe m a b -> t m a -> t m b -- | Right fold to a streaming monad. -- --
-- foldrS Stream.cons Stream.nil === id ---- -- foldrS can be used to perform stateless stream to stream -- transformations like map and filter in general. It can be coupled with -- a scan to perform stateful transformations. However, note that the -- custom map and filter routines can be much more efficient than this -- due to better stream fusion. -- --
-- >>> Stream.toList $ Stream.foldrS Stream.cons Stream.nil $ Stream.fromList [1..5] -- [1,2,3,4,5] ---- -- Find if any element in the stream is True: -- --
-- >>> Stream.toList $ Stream.foldrS (\x xs -> if odd x then (Stream.fromPure True) else xs) (Stream.fromPure False) $ (Stream.fromList (2:4:5:undefined) :: Stream.SerialT IO Int) -- [True] ---- -- Map (+2) on odd elements and filter out the even elements: -- --
-- >>> Stream.toList $ Stream.foldrS (\x xs -> if odd x then (x + 2) `Stream.cons` xs else xs) Stream.nil $ (Stream.fromList [1..5] :: Stream.SerialT IO Int) -- [3,5,7] ---- -- foldrM can also be represented in terms of foldrS, -- however, the former is much more efficient: -- --
-- foldrM f z s = runIdentityT $ foldrS (\x xs -> lift $ f x (runIdentityT xs)) (lift z) s ---- -- Pre-release foldrS :: IsStream t => (a -> t m b -> t m b) -> t m b -> t m a -> t m b foldrSShared :: IsStream t => (a -> t m b -> t m b) -> t m b -> t m a -> t m b -- | Right fold to a transformer monad. This is the most general right fold -- function. foldrS is a special case of foldrT, however -- foldrS implementation can be more efficient: -- --
-- foldrS = foldrT -- foldrM f z s = runIdentityT $ foldrT (\x xs -> lift $ f x (runIdentityT xs)) (lift z) s ---- -- foldrT can be used to translate streamly streams to other -- transformer monads e.g. to a different streaming type. -- -- Pre-release foldrT :: (IsStream t, Monad m, Monad (s m), MonadTrans s) => (a -> s m b -> s m b) -> s m b -> t m a -> s m b -- |
-- map = fmap ---- -- Same as fmap. -- --
-- > D.toList $ D.map (+1) $ D.fromList [1,2,3] -- [2,3,4] --map :: (IsStream t, Monad m) => (a -> b) -> t m a -> t m b -- |
-- sequence = mapM id ---- -- Replace the elements of a stream of monadic actions with the outputs -- of those actions. -- --
-- >>> drain $ Stream.sequence $ Stream.fromList [putStr "a", putStr "b", putStrLn "c"] -- abc -- -- >>> :{ -- drain $ Stream.replicateM 3 (return $ threadDelay 1000000 >> print 1) -- & (fromSerial . Stream.sequence) -- :} -- 1 -- 1 -- 1 -- -- >>> :{ -- drain $ Stream.replicateM 3 (return $ threadDelay 1000000 >> print 1) -- & (fromAsync . Stream.sequence) -- :} -- 1 -- 1 -- 1 ---- -- Concurrent (do not use with fromParallel on infinite -- streams) sequence :: (IsStream t, MonadAsync m) => t m (m a) -> t m a -- |
-- mapM f = sequence . map f ---- -- Apply a monadic function to each element of the stream and replace it -- with the output of the resulting action. -- --
-- >>> drain $ Stream.mapM putStr $ Stream.fromList ["a", "b", "c"] -- abc -- -- >>> :{ -- drain $ Stream.replicateM 10 (return 1) -- & (fromSerial . Stream.mapM (x -> threadDelay 1000000 >> print x)) -- :} -- 1 -- ... -- 1 -- -- > drain $ Stream.replicateM 10 (return 1) -- & (fromAsync . Stream.mapM (x -> threadDelay 1000000 >> print x)) ---- -- Concurrent (do not use with fromParallel on infinite -- streams) mapM :: forall t m a b. (IsStream t, MonadAsync m) => (a -> m b) -> t m a -> t m b -- | A stateful mapM, equivalent to a left scan, more like -- mapAccumL. Hopefully, this is a better alternative to scan. -- Separation of state from the output makes it easier to think in terms -- of a shared state, and also makes it easier to keep the state fully -- strict and the output lazy. -- -- See also: scanlM' -- -- Pre-release smapM :: (IsStream t, Monad m) => (s -> a -> m (s, b)) -> m s -> t m a -> t m b -- | Apply a monadic function to each element flowing through the stream -- and discard the results. -- --
-- >>> Stream.drain $ Stream.trace print (Stream.enumerateFromTo 1 2) -- 1 -- 2 ---- -- Compare with tap. trace :: (IsStream t, MonadAsync m) => (a -> m b) -> t m a -> t m a -- | Perform a side effect before yielding each element of the stream and -- discard the results. -- --
-- >>> Stream.drain $ Stream.trace_ (print "got here") (Stream.enumerateFromTo 1 2) -- "got here" -- "got here" ---- -- Same as intersperseMPrefix_ but always serial. -- -- See also: trace -- -- Pre-release trace_ :: (IsStream t, Monad m) => m b -> t m a -> t m a -- | Tap the data flowing through a stream into a Fold. For example, -- you may add a tap to log the contents flowing through the stream. The -- fold is used only for effects, its result is discarded. -- --
-- Fold m a b -- | -- -----stream m a ---------------stream m a----- ---- --
-- >>> Stream.drain $ Stream.tap (Fold.drainBy print) (Stream.enumerateFromTo 1 2) -- 1 -- 2 ---- -- Compare with trace. tap :: (IsStream t, Monad m) => Fold m a b -> t m a -> t m a -- | tapOffsetEvery offset n taps every nth element in -- the stream starting at offset. offset can be between -- 0 and n - 1. Offset 0 means start at the first -- element in the stream. If the offset is outside this range then -- offset mod n is used as offset. -- --
-- >>> Stream.drain $ Stream.tapOffsetEvery 0 2 (Fold.rmapM print Fold.toList) $ Stream.enumerateFromTo 0 10 -- [0,2,4,6,8,10] --tapOffsetEvery :: (IsStream t, Monad m) => Int -> Int -> Fold m a b -> t m a -> t m a -- | Redirect a copy of the stream to a supplied fold and run it -- concurrently in an independent thread. The fold may buffer some -- elements. The buffer size is determined by the prevailing -- maxBuffer setting. -- --
-- Stream m a -> m b -- | -- -----stream m a ---------------stream m a----- ---- --
-- >>> Stream.drain $ Stream.tapAsync (Fold.drainBy print) (Stream.enumerateFromTo 1 2) -- 1 -- 2 ---- -- Exceptions from the concurrently running fold are propagated to the -- current computation. Note that, because of buffering in the fold, -- exceptions may be delayed and may not correspond to the current -- element being processed in the parent stream, but we guarantee that -- before the parent stream stops the tap finishes and all exceptions -- from it are drained. -- --
-- >>> tapAsync f = Stream.tapAsyncK (Stream.fold f . Stream.adapt) ---- -- Compare with tap. -- -- Pre-release tapAsync :: (IsStream t, MonadAsync m) => Fold m a b -> t m a -> t m a -- | Like tapAsyncF but uses a stream fold function instead of a -- Fold type. -- -- Pre-release tapAsyncK :: (IsStream t, MonadAsync m) => (t m a -> m b) -> t m a -> t m a -- | Concurrently distribute a stream to a collection of fold functions, -- discarding the outputs of the folds. -- --
-- > Stream.drain $ Stream.distributeAsync_ [Stream.mapM_ print, Stream.mapM_ print] (Stream.enumerateFromTo 1 2) -- 1 -- 2 -- 1 -- 2 ---- --
-- distributeAsync_ = flip (foldr tapAsync) ---- -- Pre-release distributeAsync_ :: (Foldable f, IsStream t, MonadAsync m) => f (t m a -> m b) -> t m a -> t m a -- | pollCounts predicate transform fold stream counts those -- elements in the stream that pass the predicate. The resulting -- count stream is sent to another thread which transforms it using -- transform and then folds it using fold. The thread -- is automatically cleaned up if the stream stops or aborts due to -- exception. -- -- For example, to print the count of elements processed every second: -- --
-- > Stream.drain $ Stream.pollCounts (const True) (Stream.rollingMap (-) . Stream.delayPost 1) (FLold.drainBy print) -- $ Stream.enumerateFrom 0 ---- -- Note: This may not work correctly on 32-bit machines. -- -- Pre-release pollCounts :: (IsStream t, MonadAsync m) => (a -> Bool) -> (t m Int -> m b) -> t m a -> t m a -- | Scan a stream using the given monadic fold. -- --
-- >>> Stream.toList $ Stream.takeWhile (< 10) $ Stream.scan Fold.sum (Stream.fromList [1..10]) -- [0,1,3,6] --scan :: (IsStream t, Monad m) => Fold m a b -> t m a -> t m b -- | Like scan but restarts scanning afresh when the scanning fold -- terminates. -- -- Pre-release scanMany :: (IsStream t, Monad m) => Fold m a b -> t m a -> t m b -- | Postscan a stream using the given monadic fold. -- -- The following example extracts the input stream up to a point where -- the running average of elements is no more than 10: -- --
-- >>> import Data.Maybe (fromJust) -- -- >>> let avg = Fold.teeWith (/) Fold.sum (fmap fromIntegral Fold.length) -- -- >>> :{ -- Stream.toList -- $ Stream.map (fromJust . fst) -- $ Stream.takeWhile (\(_,x) -> x <= 10) -- $ Stream.postscan (Fold.tee Fold.last avg) (Stream.enumerateFromTo 1.0 100.0) -- :} -- [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0,16.0,17.0,18.0,19.0] --postscan :: (IsStream t, Monad m) => Fold m a b -> t m a -> t m b -- | Strict left scan. Like map, scanl' too is a one to one -- transformation, however it adds an extra element. -- --
-- >>> Stream.toList $ Stream.scanl' (+) 0 $ fromList [1,2,3,4] -- [0,1,3,6,10] ---- --
-- >>> Stream.toList $ Stream.scanl' (flip (:)) [] $ Stream.fromList [1,2,3,4] -- [[],[1],[2,1],[3,2,1],[4,3,2,1]] ---- -- The output of scanl' is the initial value of the accumulator -- followed by all the intermediate steps and the final result of -- foldl'. -- -- By streaming the accumulated state after each fold step, we can share -- the state across multiple stages of stream composition. Each stage can -- modify or extend the state, do some processing with it and emit it for -- the next stage, thus modularizing the stream processing. This can be -- useful in stateful or event-driven programming. -- -- Consider the following monolithic example, computing the sum and the -- product of the elements in a stream in one go using a foldl': -- --
-- >>> Stream.foldl' ((s, p) x -> (s + x, p * x)) (0,1) $ Stream.fromList 1,2,3,4 ---- -- Using scanl' we can make it modular by computing the sum in -- the first stage and passing it down to the next stage for computing -- the product: -- --
-- >>> :{ -- Stream.foldl' ((_, p) (s, x) -> (s, p * x)) (0,1) -- $ Stream.scanl' ((s, _) x -> (s + x, x)) (0,1) -- $ Stream.fromList [1,2,3,4] -- :} -- (10,24) ---- -- IMPORTANT: scanl' evaluates the accumulator to WHNF. To avoid -- building lazy expressions inside the accumulator, it is recommended -- that a strict data structure is used for accumulator. -- --
-- >>> scanl' step z = scan (Fold.foldl' step z) -- -- >>> scanl' f z xs = scanlM' (\a b -> return (f a b)) (return z) xs -- -- >>> scanl' f z xs = z `Stream.cons` postscanl' f z xs ---- -- See also: usingStateT scanl' :: (IsStream t, Monad m) => (b -> a -> b) -> b -> t m a -> t m b -- | Like scanl' but with a monadic step function and a monadic -- seed. -- -- Since: 0.4.0 -- -- Since: 0.8.0 (signature change) scanlM' :: (IsStream t, Monad m) => (b -> a -> m b) -> m b -> t m a -> t m b -- | scanlMAfter' accumulate initial done stream is like -- scanlM' except that it provides an additional done -- function to be applied on the accumulator when the stream stops. The -- result of done is also emitted in the stream. -- -- This function can be used to allocate a resource in the beginning of -- the scan and release it when the stream ends or to flush the internal -- state of the scan at the end. -- -- Pre-release scanlMAfter' :: (IsStream t, Monad m) => (b -> a -> m b) -> m b -> (b -> m b) -> t m a -> t m b postscanlMAfter' :: (IsStream t, Monad m) => (b -> a -> m b) -> m b -> (b -> m b) -> t m a -> t m b -- | Like scanl' but does not stream the initial value of the -- accumulator. -- --
-- >>> postscanl' step z = postscan (Fold.foldl' step z) -- -- >>> postscanl' f z = postscanlM' (\a b -> return (f a b)) (return z) -- -- >>> postscanl' f z xs = Stream.drop 1 $ Stream.scanl' f z xs --postscanl' :: (IsStream t, Monad m) => (b -> a -> b) -> b -> t m a -> t m b -- | Like postscanl' but with a monadic step function and a -- monadic seed. -- --
-- >>> postscanlM' f z xs = Stream.drop 1 $ Stream.scanlM' f z xs ---- -- Since: 0.7.0 -- -- Since: 0.8.0 (signature change) postscanlM' :: (IsStream t, Monad m) => (b -> a -> m b) -> m b -> t m a -> t m b -- | Like scanl' but does not stream the final value of the accumulator. -- -- Pre-release prescanl' :: (IsStream t, Monad m) => (b -> a -> b) -> b -> t m a -> t m b -- | Like prescanl' but with a monadic step function and a monadic seed. -- -- Pre-release prescanlM' :: (IsStream t, Monad m) => (b -> a -> m b) -> m b -> t m a -> t m b -- | Like scanl' but for a non-empty stream. The first element of -- the stream is used as the initial value of the accumulator. Does -- nothing if the stream is empty. -- --
-- >>> Stream.toList $ Stream.scanl1' (+) $ fromList [1,2,3,4] -- [1,3,6,10] --scanl1' :: (IsStream t, Monad m) => (a -> a -> a) -> t m a -> t m a -- | Like scanl1' but with a monadic step function. scanl1M' :: (IsStream t, Monad m) => (a -> a -> m a) -> t m a -> t m a -- | Modify a t m a -> t m a stream transformation that accepts -- a predicate (a -> b) to accept ((s, a) -> b) -- instead, provided a transformation t m a -> t m (s, a). -- Convenient to filter with index or time. -- --
-- filterWithIndex = with indexed filter -- filterWithAbsTime = with timestamped filter -- filterWithRelTime = with timeIndexed filter ---- -- Pre-release with :: forall (t :: (Type -> Type) -> Type -> Type) m a b s. Functor (t m) => (t m a -> t m (s, a)) -> (((s, a) -> b) -> t m (s, a) -> t m (s, a)) -> ((s, a) -> b) -> t m a -> t m a -- | Deletes the first occurrence of the element in the stream that -- satisfies the given equality predicate. -- --
-- >>> Stream.toList $ Stream.deleteBy (==) 3 $ Stream.fromList [1,3,3,5] -- [1,3,5] --deleteBy :: (IsStream t, Monad m) => (a -> a -> Bool) -> a -> t m a -> t m a -- | Include only those elements that pass a predicate. filter :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> t m a -- | Same as filter but with a monadic predicate. filterM :: (IsStream t, Monad m) => (a -> m Bool) -> t m a -> t m a -- | Drop repeated elements that are adjacent to each other. uniq :: (Eq a, IsStream t, Monad m) => t m a -> t m a -- | Drop repeated elements that are adjacent to each other using the -- supplied comparison function. -- -- @uniq = uniqBy (==) -- -- To strip duplicate path separators: -- --
-- f x y = x == / && x == y -- Stream.toList $ Stream.uniqBy f $ Stream.fromList "/a/b" -- "ab" ---- -- Space: O(1) -- -- See also: nubBy. -- -- Pre-release uniqBy :: (IsStream t, Monad m, Functor (t m)) => (a -> a -> Bool) -> t m a -> t m a -- | Drop repeated elements anywhere in the stream. -- -- Caution: not scalable for infinite streams -- -- See also: nubWindowBy -- -- Unimplemented nubBy :: (a -> a -> Bool) -> t m a -> t m a -- | Strip all leading and trailing occurrences of an element passing a -- predicate and make all other consecutive occurrences uniq. -- --
-- prune p = dropWhileAround p $ uniqBy (x y -> p x && p y) ---- --
-- > Stream.prune isSpace (Stream.fromList " hello world! ") -- "hello world!" ---- -- Space: O(1) -- -- Unimplemented prune :: (a -> Bool) -> t m a -> t m a -- | Emit only repeated elements, once. -- -- Unimplemented repeated :: t m a -> t m a -- | Take first n elements from the stream and discard the rest. take :: (IsStream t, Monad m) => Int -> t m a -> t m a -- | Take n elements at the end of the stream. -- -- O(n) space, where n is the number elements taken. -- -- Unimplemented takeLast :: Int -> t m a -> t m a -- | Take time interval i seconds at the end of the stream. -- -- O(n) space, where n is the number elements taken. -- -- Unimplemented takeLastInterval :: Double -> t m a -> t m a -- | End the stream as soon as the predicate fails on an element. takeWhile :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> t m a -- | Same as takeWhile but with a monadic predicate. takeWhileM :: (IsStream t, Monad m) => (a -> m Bool) -> t m a -> t m a -- | Take all consecutive elements at the end of the stream for which the -- predicate is true. -- -- O(n) space, where n is the number elements taken. -- -- Unimplemented takeWhileLast :: (a -> Bool) -> t m a -> t m a -- | Like takeWhile and takeWhileLast combined. -- -- O(n) space, where n is the number elements taken from the end. -- -- Unimplemented takeWhileAround :: (a -> Bool) -> t m a -> t m a -- | Discard first n elements from the stream and take the rest. drop :: (IsStream t, Monad m) => Int -> t m a -> t m a -- | Drop n elements at the end of the stream. -- -- O(n) space, where n is the number elements dropped. -- -- Unimplemented dropLast :: Int -> t m a -> t m a -- | Drop time interval i seconds at the end of the stream. -- -- O(n) space, where n is the number elements dropped. -- -- Unimplemented dropLastInterval :: Int -> t m a -> t m a -- | Drop elements in the stream as long as the predicate succeeds and then -- take the rest of the stream. dropWhile :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> t m a -- | Same as dropWhile but with a monadic predicate. dropWhileM :: (IsStream t, Monad m) => (a -> m Bool) -> t m a -> t m a -- | Drop all consecutive elements at the end of the stream for which the -- predicate is true. -- -- O(n) space, where n is the number elements dropped. -- -- Unimplemented dropWhileLast :: (a -> Bool) -> t m a -> t m a -- | Like dropWhile and dropWhileLast combined. -- -- O(n) space, where n is the number elements dropped from the end. -- -- Unimplemented dropWhileAround :: (a -> Bool) -> t m a -> t m a -- | Insert a pure value between successive elements of a stream. -- --
-- >>> Stream.toList $ Stream.intersperse ',' $ Stream.fromList "hello" -- "h,e,l,l,o" --intersperse :: (IsStream t, MonadAsync m) => a -> t m a -> t m a -- | Insert an effect and its output before consuming an element of a -- stream except the first one. -- --
-- >>> Stream.toList $ Stream.trace putChar $ Stream.intersperseM (putChar '.' >> return ',') $ Stream.fromList "hello" -- h.,e.,l.,l.,o"h,e,l,l,o" ---- -- Be careful about the order of effects. In the above example we used -- trace after the intersperse, if we use it before the intersperse the -- output would be he.l.l.o."h,e,l,l,o". -- --
-- >>> Stream.toList $ Stream.intersperseM (putChar '.' >> return ',') $ Stream.trace putChar $ Stream.fromList "hello" -- he.l.l.o."h,e,l,l,o" --intersperseM :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a -- | Intersperse a monadic action into the input stream after every -- n elements. -- --
-- > Stream.toList $ Stream.intersperseMWith 2 (return ',') $ Stream.fromList "hello" -- "he,ll,o" ---- -- Unimplemented intersperseMWith :: Int -> m a -> t m a -> t m a -- | Insert an effect and its output after consuming an element of a -- stream. -- --
-- >>> Stream.toList $ Stream.trace putChar $ intersperseMSuffix (putChar '.' >> return ',') $ Stream.fromList "hello" -- h.,e.,l.,l.,o.,"h,e,l,l,o," ---- -- Pre-release intersperseMSuffix :: (IsStream t, Monad m) => m a -> t m a -> t m a -- | Like intersperseMSuffix but intersperses an effectful action -- into the input stream after every n elements and after the -- last element. -- --
-- >>> Stream.toList $ Stream.intersperseMSuffixWith 2 (return ',') $ Stream.fromList "hello" -- "he,ll,o," ---- -- Pre-release intersperseMSuffixWith :: (IsStream t, Monad m) => Int -> m a -> t m a -> t m a -- | Intersperse a monadic action into the input stream after every -- n seconds. -- --
-- > import Control.Concurrent (threadDelay) -- > Stream.drain $ Stream.interjectSuffix 1 (putChar ',') $ Stream.mapM (x -> threadDelay 1000000 >> putChar x) $ Stream.fromList "hello" -- h,e,l,l,o ---- -- Pre-release interjectSuffix :: (IsStream t, MonadAsync m) => Double -> m a -> t m a -> t m a -- | Insert a side effect before consuming an element of a stream except -- the first one. -- --
-- >>> Stream.drain $ Stream.trace putChar $ Stream.intersperseM_ (putChar '.') $ Stream.fromList "hello" -- h.e.l.l.o ---- -- Pre-release intersperseM_ :: (IsStream t, Monad m) => m b -> t m a -> t m a -- | Introduce a delay of specified seconds before consuming an element of -- the stream except the first one. -- --
-- >>> Stream.mapM_ print $ Stream.timestamped $ Stream.delay 1 $ Stream.enumerateFromTo 1 3 -- (AbsTime (TimeSpec {sec = ..., nsec = ...}),1) -- (AbsTime (TimeSpec {sec = ..., nsec = ...}),2) -- (AbsTime (TimeSpec {sec = ..., nsec = ...}),3) --delay :: (IsStream t, MonadIO m) => Double -> t m a -> t m a -- | Insert a side effect after consuming an element of a stream. -- --
-- >>> Stream.mapM_ putChar $ Stream.intersperseMSuffix_ (threadDelay 1000000) $ Stream.fromList "hello" -- hello ---- -- Pre-release intersperseMSuffix_ :: (IsStream t, Monad m) => m b -> t m a -> t m a -- | Introduce a delay of specified seconds after consuming an element of a -- stream. -- --
-- >>> Stream.mapM_ print $ Stream.timestamped $ Stream.delayPost 1 $ Stream.enumerateFromTo 1 3 -- (AbsTime (TimeSpec {sec = ..., nsec = ...}),1) -- (AbsTime (TimeSpec {sec = ..., nsec = ...}),2) -- (AbsTime (TimeSpec {sec = ..., nsec = ...}),3) ---- -- Pre-release delayPost :: (IsStream t, MonadIO m) => Double -> t m a -> t m a -- | Insert a side effect before consuming an element of a stream. -- --
-- >>> Stream.toList $ Stream.trace putChar $ Stream.intersperseMPrefix_ (putChar '.' >> return ',') $ Stream.fromList "hello" -- .h.e.l.l.o"hello" ---- -- Same as trace_ but may be concurrent. -- -- Concurrent -- -- Pre-release intersperseMPrefix_ :: (IsStream t, MonadAsync m) => m b -> t m a -> t m a -- | Introduce a delay of specified seconds before consuming an element of -- a stream. -- --
-- >>> Stream.mapM_ print $ Stream.timestamped $ Stream.delayPre 1 $ Stream.enumerateFromTo 1 3 -- (AbsTime (TimeSpec {sec = ..., nsec = ...}),1) -- (AbsTime (TimeSpec {sec = ..., nsec = ...}),2) -- (AbsTime (TimeSpec {sec = ..., nsec = ...}),3) ---- -- Pre-release delayPre :: (IsStream t, MonadIO m) => Double -> t m a -> t m a -- | insertBy cmp elem stream inserts elem before the -- first element in stream that is less than elem when -- compared using cmp. -- --
-- insertBy cmp x = mergeBy cmp (fromPure x) ---- --
-- >>> Stream.toList $ Stream.insertBy compare 2 $ Stream.fromList [1,3,5] -- [1,2,3,5] --insertBy :: (IsStream t, Monad m) => (a -> a -> Ordering) -> a -> t m a -> t m a -- | Returns the elements of the stream in reverse order. The stream must -- be finite. Note that this necessarily buffers the entire stream in -- memory. -- --
-- >>> reverse = Stream.foldlT (flip Stream.cons) Stream.nil ---- -- Since 0.7.0 (Monad m constraint) -- -- Since: 0.1.1 reverse :: (IsStream t, Monad m) => t m a -> t m a -- | Like reverse but several times faster, requires a -- Storable instance. -- -- Pre-release reverse' :: (IsStream t, MonadIO m, Unbox a) => t m a -> t m a -- | Buffer until the next element in sequence arrives. The function -- argument determines the difference in sequence numbers. This could be -- useful in implementing sequenced streams, for example, TCP reassembly. -- -- Unimplemented reassembleBy :: Fold m a b -> (a -> a -> Int) -> t m a -> t m b -- |
-- indexed = Stream.postscanl' (\(i, _) x -> (i + 1, x)) (-1,undefined) -- indexed = Stream.zipWith (,) (Stream.enumerateFrom 0) ---- -- Pair each element in a stream with its index, starting from index 0. -- --
-- >>> Stream.toList $ Stream.indexed $ Stream.fromList "hello" -- [(0,'h'),(1,'e'),(2,'l'),(3,'l'),(4,'o')] --indexed :: (IsStream t, Monad m) => t m a -> t m (Int, a) -- |
-- indexedR n = Stream.postscanl' (\(i, _) x -> (i - 1, x)) (n + 1,undefined) -- indexedR n = Stream.zipWith (,) (Stream.enumerateFromThen n (n - 1)) ---- -- Pair each element in a stream with its index, starting from the given -- index n and counting down. -- --
-- >>> Stream.toList $ Stream.indexedR 10 $ Stream.fromList "hello" -- [(10,'h'),(9,'e'),(8,'l'),(7,'l'),(6,'o')] --indexedR :: (IsStream t, Monad m) => Int -> t m a -> t m (Int, a) timestamped :: (IsStream t, MonadAsync m, Functor (t m)) => t m a -> t m (AbsTime, a) -- | Pair each element in a stream with an absolute timestamp, using a -- clock of specified granularity. The timestamp is generated just before -- the element is consumed. -- --
-- >>> Stream.mapM_ print $ Stream.timestampWith 0.01 $ Stream.delay 1 $ Stream.enumerateFromTo 1 3 -- (AbsTime (TimeSpec {sec = ..., nsec = ...}),1) -- (AbsTime (TimeSpec {sec = ..., nsec = ...}),2) -- (AbsTime (TimeSpec {sec = ..., nsec = ...}),3) ---- -- Pre-release timestampWith :: (IsStream t, MonadAsync m, Functor (t m)) => Double -> t m a -> t m (AbsTime, a) -- | Pair each element in a stream with relative times starting from 0, -- using a 10 ms granularity clock. The time is measured just before the -- element is consumed. -- --
-- >>> Stream.mapM_ print $ Stream.timeIndexed $ Stream.delay 1 $ Stream.enumerateFromTo 1 3 -- (RelTime64 (NanoSecond64 ...),1) -- (RelTime64 (NanoSecond64 ...),2) -- (RelTime64 (NanoSecond64 ...),3) ---- -- Pre-release timeIndexed :: (IsStream t, MonadAsync m, Functor (t m)) => t m a -> t m (RelTime64, a) -- | Pair each element in a stream with relative times starting from 0, -- using a clock with the specified granularity. The time is measured -- just before the element is consumed. -- --
-- >>> Stream.mapM_ print $ Stream.timeIndexWith 0.01 $ Stream.delay 1 $ Stream.enumerateFromTo 1 3 -- (RelTime64 (NanoSecond64 ...),1) -- (RelTime64 (NanoSecond64 ...),2) -- (RelTime64 (NanoSecond64 ...),3) ---- -- Pre-release timeIndexWith :: (IsStream t, MonadAsync m, Functor (t m)) => Double -> t m a -> t m (RelTime64, a) -- | Find all the indices where the element in the stream satisfies the -- given predicate. -- --
-- findIndices = fold Fold.findIndices --findIndices :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> t m Int -- | Find all the indices where the value of the element in the stream is -- equal to the given value. -- --
-- elemIndices a = findIndices (== a) --elemIndices :: (IsStream t, Eq a, Monad m) => a -> t m a -> t m Int -- | Like rollingMap but with an effectful map function. -- -- Pre-release rollingMapM :: (IsStream t, Monad m) => (Maybe a -> a -> m b) -> t m a -> t m b -- | Apply a function on every two successive elements of a stream. The -- first argument of the map function is the previous element and the -- second argument is the current element. When the current element is -- the first element, the previous element is Nothing. -- -- Pre-release rollingMap :: (IsStream t, Monad m) => (Maybe a -> a -> b) -> t m a -> t m b -- | Like rollingMap but requires at least two elements in the -- stream, returns an empty stream otherwise. -- -- This is the stream equivalent of the list idiom zipWith f xs (tail -- xs). -- -- Pre-release rollingMap2 :: (IsStream t, Monad m) => (a -> a -> b) -> t m a -> t m b -- | In a stream of Maybes, discard Nothings and unwrap -- Justs. -- -- Pre-release catMaybes :: (IsStream t, Monad m, Functor (t m)) => t m (Maybe a) -> t m a -- | Map a Maybe returning function to a stream, filter out the -- Nothing elements, and return a stream of values extracted from -- Just. -- -- Equivalent to: -- --
-- mapMaybe f = Stream.map fromJust . Stream.filter isJust . Stream.map f --mapMaybe :: (IsStream t, Monad m) => (a -> Maybe b) -> t m a -> t m b -- | Like mapMaybe but maps a monadic function. -- -- Equivalent to: -- --
-- mapMaybeM f = Stream.map fromJust . Stream.filter isJust . Stream.mapM f ---- -- Concurrent (do not use with fromParallel on infinite -- streams) mapMaybeM :: (IsStream t, MonadAsync m, Functor (t m)) => (a -> m (Maybe b)) -> t m a -> t m b -- | Discard Rights and unwrap Lefts in an Either -- stream. -- -- Pre-release lefts :: (IsStream t, Monad m, Functor (t m)) => t m (Either a b) -> t m a -- | Discard Lefts and unwrap Rights in an Either -- stream. -- -- Pre-release rights :: (IsStream t, Monad m, Functor (t m)) => t m (Either a b) -> t m b -- | Remove the either wrapper and flatten both lefts and as well as rights -- in the output stream. -- -- Pre-release both :: Functor (t m) => t m (Either a a) -> t m a -- | Make the stream producer and consumer run concurrently by introducing -- a buffer between them. The producer thread evaluates the input stream -- until the buffer fills, it terminates if the buffer is full and a -- worker thread is kicked off again to evaluate the remaining stream -- when there is space in the buffer. The consumer consumes the stream -- lazily from the buffer. -- -- Since: 0.2.0 (Streamly) mkAsync :: (IsStream t, MonadAsync m) => t m a -> t m a -- | Make the stream producer and consumer run concurrently by introducing -- a buffer between them. The producer thread evaluates the input stream -- until the buffer fills, it blocks if the buffer is full until there is -- space in the buffer. The consumer consumes the stream lazily from the -- buffer. -- --
-- mkParallel = IsStream.fromStreamD . mkParallelD . IsStream.toStreamD ---- -- Pre-release mkParallel :: (IsStream t, MonadAsync m) => t m a -> t m a -- | Same as |$. -- -- Internal applyAsync :: (IsStream t, MonadAsync m) => (t m a -> t m b) -> t m a -> t m b -- | Parallel transform application operator; applies a stream -- transformation function t m a -> t m b to a stream t m -- a concurrently; the input stream is evaluated asynchronously in -- an independent thread yielding elements to a buffer and the -- transformation function runs in another thread consuming the input -- from the buffer. |$ is just like regular function application -- operator $ except that it is concurrent. -- -- If you read the signature as (t m a -> t m b) -> (t m a -- -> t m b) you can look at it as a transformation that converts -- a transform function to a buffered concurrent transform function. -- -- The following code prints a value every second even though each stage -- adds a 1 second delay. -- --
-- >>> :{ -- Stream.drain $ -- Stream.mapM (\x -> threadDelay 1000000 >> print x) -- |$ Stream.replicateM 3 (threadDelay 1000000 >> return 1) -- :} -- 1 -- 1 -- 1 ---- -- Concurrent -- -- Since: 0.3.0 (Streamly) (|$) :: (IsStream t, MonadAsync m) => (t m a -> t m b) -> t m a -> t m b infixr 0 |$ -- | Same as |$ but with arguments reversed. -- -- (|&) = flip (|$) -- -- Concurrent -- -- Since: 0.3.0 (Streamly) (|&) :: (IsStream t, MonadAsync m) => t m a -> (t m a -> t m b) -> t m b infixl 1 |& -- | Specify the maximum number of threads that can be spawned concurrently -- for any concurrent combinator in a stream. A value of 0 resets the -- thread limit to default, a negative value means there is no limit. The -- default value is 1500. maxThreads does not affect -- ParallelT streams as they can use unbounded number of -- threads. -- -- When the actions in a stream are IO bound, having blocking IO calls, -- this option can be used to control the maximum number of in-flight IO -- requests. When the actions are CPU bound this option can be used to -- control the amount of CPU used by the stream. -- -- Since: 0.4.0 (Streamly) maxThreads :: IsStream t => Int -> t m a -> t m a -- | Specify the maximum size of the buffer for storing the results from -- concurrent computations. If the buffer becomes full we stop spawning -- more concurrent tasks until there is space in the buffer. A value of 0 -- resets the buffer size to default, a negative value means there is no -- limit. The default value is 1500. -- -- CAUTION! using an unbounded maxBuffer value (i.e. a negative -- value) coupled with an unbounded maxThreads value is a recipe -- for disaster in presence of infinite streams, or very large streams. -- Especially, it must not be used when pure is used in -- ZipAsyncM streams as pure in applicative zip streams -- generates an infinite stream causing unbounded concurrent generation -- with no limit on the buffer or threads. -- -- Since: 0.4.0 (Streamly) maxBuffer :: IsStream t => Int -> t m a -> t m a -- | Evaluate the input stream continuously and keep only the oldest -- n elements in the buffer, discard the new ones when the -- buffer is full. When the output stream is evaluated it consumes the -- values from the buffer in a FIFO manner. -- -- Unimplemented sampleOld :: Int -> t m a -> t m a -- | Evaluate the input stream continuously and keep only the latest -- n elements in a ring buffer, keep discarding the older ones -- to make space for the new ones. When the output stream is evaluated it -- consumes the values from the buffer in a FIFO manner. -- -- Unimplemented sampleNew :: Int -> t m a -> t m a -- | Like sampleNew but samples at uniform intervals to match the -- consumer rate. Note that sampleNew leads to non-uniform -- sampling depending on the consumer pattern. -- -- Unimplemented sampleRate :: Double -> t m a -> t m a data Rate Rate :: Double -> Double -> Double -> Int -> Rate [rateLow] :: Rate -> Double [rateGoal] :: Rate -> Double [rateHigh] :: Rate -> Double [rateBuffer] :: Rate -> Int -- | Specify the pull rate of a stream. A Nothing value resets the -- rate to default which is unlimited. When the rate is specified, -- concurrent production may be ramped up or down automatically to -- achieve the specified yield rate. The specific behavior for different -- styles of Rate specifications is documented under Rate. -- The effective maximum production rate achieved by a stream is governed -- by: -- --
-- >>> import Streamly.Prelude (serial) -- -- >>> stream1 = Stream.fromList [1,2] -- -- >>> stream2 = Stream.fromList [3,4] -- -- >>> Stream.toList $ stream1 `serial` stream2 -- [1,2,3,4] ---- -- This operation can be used to fold an infinite lazy container of -- streams. -- -- Since: 0.2.0 (Streamly) serial :: IsStream t => t m a -> t m a -> t m a infixr 6 `serial` -- | Appends two streams, both the streams may be evaluated concurrently -- but the outputs are used in the same order as the corresponding -- actions in the original streams, side effects will happen in the order -- in which the streams are evaluated: -- --
-- >>> import Streamly.Prelude (ahead, SerialT) -- -- >>> stream1 = Stream.fromEffect (delay 4) :: SerialT IO Int -- -- >>> stream2 = Stream.fromEffect (delay 2) :: SerialT IO Int -- -- >>> Stream.toList $ stream1 `ahead` stream2 :: IO [Int] -- 2 sec -- 4 sec -- [4,2] ---- -- Multiple streams can be combined. With enough threads, all of them can -- be scheduled simultaneously: -- --
-- >>> stream3 = Stream.fromEffect (delay 1) -- -- >>> Stream.toList $ stream1 `ahead` stream2 `ahead` stream3 -- 1 sec -- 2 sec -- 4 sec -- [4,2,1] ---- -- With 2 threads, only two can be scheduled at a time, when one of those -- finishes, the third one gets scheduled: -- --
-- >>> Stream.toList $ Stream.maxThreads 2 $ stream1 `ahead` stream2 `ahead` stream3 -- 2 sec -- 1 sec -- 4 sec -- [4,2,1] ---- -- Only streams are scheduled for ahead evaluation, how actions within a -- stream are evaluated depends on the stream type. If it is a concurrent -- stream they will be evaluated concurrently. It may not make much sense -- combining serial streams using ahead. -- -- ahead can be safely used to fold an infinite lazy container of -- streams. -- -- Since: 0.3.0 (Streamly) ahead :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a infixr 6 `ahead` -- | Merges two streams, both the streams may be evaluated concurrently, -- outputs from both are used as they arrive: -- --
-- >>> import Streamly.Prelude (async) -- -- >>> stream1 = Stream.fromEffect (delay 4) -- -- >>> stream2 = Stream.fromEffect (delay 2) -- -- >>> Stream.toList $ stream1 `async` stream2 -- 2 sec -- 4 sec -- [2,4] ---- -- Multiple streams can be combined. With enough threads, all of them can -- be scheduled simultaneously: -- --
-- >>> stream3 = Stream.fromEffect (delay 1) -- -- >>> Stream.toList $ stream1 `async` stream2 `async` stream3 -- ... -- [1,2,4] ---- -- With 2 threads, only two can be scheduled at a time, when one of those -- finishes, the third one gets scheduled: -- --
-- >>> Stream.toList $ Stream.maxThreads 2 $ stream1 `async` stream2 `async` stream3 -- ... -- [2,1,4] ---- -- With a single thread, it becomes serial: -- --
-- >>> Stream.toList $ Stream.maxThreads 1 $ stream1 `async` stream2 `async` stream3 -- ... -- [4,2,1] ---- -- Only streams are scheduled for async evaluation, how actions within a -- stream are evaluated depends on the stream type. If it is a concurrent -- stream they will be evaluated concurrently. -- -- In the following example, both the streams are scheduled for -- concurrent evaluation but each individual stream is evaluated -- serially: -- --
-- >>> stream1 = Stream.fromListM $ Prelude.map delay [3,3] -- SerialT IO Int -- -- >>> stream2 = Stream.fromListM $ Prelude.map delay [1,1] -- SerialT IO Int -- -- >>> Stream.toList $ stream1 `async` stream2 -- IO [Int] -- ... -- [1,1,3,3] ---- -- If total threads are 2, the third stream is scheduled only after one -- of the first two has finished: -- --
-- stream3 = Stream.fromListM $ Prelude.map delay [2,2] -- SerialT IO Int -- Stream.toList $ Stream.maxThreads 2 $ stream1 `async` stream2 `async` stream3 -- IO [Int] ---- -- ... [1,1,3,2,3,2] -- -- Thus async goes deep in first few streams rather than going -- wide in all streams. It prefers to evaluate the leftmost streams as -- much as possible. Because of this behavior, async can be safely -- used to fold an infinite lazy container of streams. -- -- Since: 0.2.0 (Streamly) async :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a infixr 6 `async` -- | For singleton streams, wAsync is the same as async. See -- async for singleton stream behavior. For multi-element streams, -- while async is left biased i.e. it tries to evaluate the left -- side stream as much as possible, wAsync tries to schedule them -- both fairly. In other words, async goes deep while -- wAsync goes wide. However, outputs are always used as they -- arrive. -- -- With a single thread, async starts behaving like serial -- while wAsync starts behaving like wSerial. -- --
-- >>> import Streamly.Prelude (async, wAsync) -- -- >>> stream1 = Stream.fromList [1,2,3] -- -- >>> stream2 = Stream.fromList [4,5,6] -- -- >>> Stream.toList $ Stream.fromAsync $ Stream.maxThreads 1 $ stream1 `async` stream2 -- [1,2,3,4,5,6] ---- --
-- >>> Stream.toList $ Stream.fromWAsync $ Stream.maxThreads 1 $ stream1 `wAsync` stream2 -- [1,4,2,5,3,6] ---- -- With two threads available, and combining three streams: -- --
-- >>> stream3 = Stream.fromList [7,8,9] -- -- >>> Stream.toList $ Stream.fromAsync $ Stream.maxThreads 2 $ stream1 `async` stream2 `async` stream3 -- [1,2,3,4,5,6,7,8,9] ---- --
-- >>> Stream.toList $ Stream.fromWAsync $ Stream.maxThreads 2 $ stream1 `wAsync` stream2 `wAsync` stream3 -- [1,4,2,7,5,3,8,6,9] ---- -- This operation cannot be used to fold an infinite lazy container of -- streams, because it schedules all the streams in a round robin manner. -- -- Note that WSerialT and single threaded WAsyncT both -- interleave streams but the exact scheduling is slightly different in -- both cases. -- -- Since: 0.2.0 (Streamly) wAsync :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a infixr 6 `wAsync` -- | Like async except that the execution is much more strict. There -- is no limit on the number of threads. While async may not -- schedule a stream if there is no demand from the consumer, -- parallel always evaluates both the streams immediately. The -- only limit that applies to parallel is maxBuffer. -- Evaluation may block if the output buffer becomes full. -- --
-- >>> import Streamly.Prelude (parallel) -- -- >>> stream = Stream.fromEffect (delay 2) `parallel` Stream.fromEffect (delay 1) -- -- >>> Stream.toList stream -- IO [Int] -- 1 sec -- 2 sec -- [1,2] ---- -- parallel guarantees that all the streams are scheduled for -- execution immediately, therefore, we could use things like starting -- timers inside the streams and relying on the fact that all timers were -- started at the same time. -- -- Unlike async this operation cannot be used to fold an infinite -- lazy container of streams, because it schedules all the streams -- strictly concurrently. -- -- Since: 0.2.0 (Streamly) parallel :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a infixr 6 `parallel` -- | Like parallel but stops the output as soon as the first -- stream stops. -- -- Pre-release parallelFst :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a -- | Like parallel but stops the output as soon as any of the two -- streams stops. -- -- Pre-release parallelMin :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a -- | Append the outputs of two streams, yielding all the elements from the -- first stream and then yielding all the elements from the second -- stream. -- -- IMPORTANT NOTE: This could be 100x faster than -- serial/<> for appending a few (say 100) streams because -- it can fuse via stream fusion. However, it does not scale for a large -- number of streams (say 1000s) and becomes qudartically slow. Therefore -- use this for custom appending of a few streams but use -- concatMap or 'concatMapWith serial' for appending n -- streams or infinite containers of streams. -- -- Pre-release append :: (IsStream t, Monad m) => t m b -> t m b -> t m b -- | Interleaves two streams, yielding one element from each stream -- alternately. When one stream stops the rest of the other stream is -- used in the output stream. -- --
-- >>> import Streamly.Prelude (wSerial) -- -- >>> stream1 = Stream.fromList [1,2] -- -- >>> stream2 = Stream.fromList [3,4] -- -- >>> Stream.toList $ Stream.fromWSerial $ stream1 `wSerial` stream2 -- [1,3,2,4] ---- -- Note, for singleton streams wSerial and serial are -- identical. -- -- Note that this operation cannot be used to fold a container of -- infinite streams but it can be used for very large streams as the -- state that it needs to maintain is proportional to the logarithm of -- the number of streams. -- -- Since: 0.2.0 (Streamly) wSerial :: IsStream t => t m a -> t m a -> t m a infixr 6 `wSerial` wSerialFst :: WSerialT m a -> WSerialT m a -> WSerialT m a wSerialMin :: WSerialT m a -> WSerialT m a -> WSerialT m a -- | Interleaves the outputs of two streams, yielding elements from each -- stream alternately, starting from the first stream. If any of the -- streams finishes early the other stream continues alone until it too -- finishes. -- --
-- >>> :set -XOverloadedStrings -- -- >>> import Data.Functor.Identity (Identity) -- -- >>> Stream.interleave "ab" ",,,," :: Stream.SerialT Identity Char -- fromList "a,b,,," ---- --
-- >>> Stream.interleave "abcd" ",," :: Stream.SerialT Identity Char -- fromList "a,b,cd" ---- -- interleave is dual to interleaveMin, it can be called -- interleaveMax. -- -- Do not use at scale in concatMapWith. -- -- Pre-release interleave :: (IsStream t, Monad m) => t m b -> t m b -> t m b -- | Interleaves the outputs of two streams, yielding elements from each -- stream alternately, starting from the first stream. The output stops -- as soon as any of the two streams finishes, discarding the remaining -- part of the other stream. The last element of the resulting stream -- would be from the longer stream. -- --
-- >>> :set -XOverloadedStrings -- -- >>> import Data.Functor.Identity (Identity) -- -- >>> Stream.interleaveMin "ab" ",,,," :: Stream.SerialT Identity Char -- fromList "a,b," -- -- >>> Stream.interleaveMin "abcd" ",," :: Stream.SerialT Identity Char -- fromList "a,b,c" ---- -- interleaveMin is dual to interleave. -- -- Do not use at scale in concatMapWith. -- -- Pre-release interleaveMin :: (IsStream t, Monad m) => t m b -> t m b -> t m b -- | Interleaves the outputs of two streams, yielding elements from each -- stream alternately, starting from the first stream. As soon as the -- first stream finishes, the output stops, discarding the remaining part -- of the second stream. In this case, the last element in the resulting -- stream would be from the second stream. If the second stream finishes -- early then the first stream still continues to yield elements until it -- finishes. -- --
-- >>> :set -XOverloadedStrings -- -- >>> import Data.Functor.Identity (Identity) -- -- >>> Stream.interleaveSuffix "abc" ",,,," :: Stream.SerialT Identity Char -- fromList "a,b,c," -- -- >>> Stream.interleaveSuffix "abc" "," :: Stream.SerialT Identity Char -- fromList "a,bc" ---- -- interleaveSuffix is a dual of interleaveInfix. -- -- Do not use at scale in concatMapWith. -- -- Pre-release interleaveSuffix :: (IsStream t, Monad m) => t m b -> t m b -> t m b -- | Interleaves the outputs of two streams, yielding elements from each -- stream alternately, starting from the first stream and ending at the -- first stream. If the second stream is longer than the first, elements -- from the second stream are infixed with elements from the first -- stream. If the first stream is longer then it continues yielding -- elements even after the second stream has finished. -- --
-- >>> :set -XOverloadedStrings -- -- >>> import Data.Functor.Identity (Identity) -- -- >>> Stream.interleaveInfix "abc" ",,,," :: Stream.SerialT Identity Char -- fromList "a,b,c" -- -- >>> Stream.interleaveInfix "abc" "," :: Stream.SerialT Identity Char -- fromList "a,bc" ---- -- interleaveInfix is a dual of interleaveSuffix. -- -- Do not use at scale in concatMapWith. -- -- Pre-release interleaveInfix :: (IsStream t, Monad m) => t m b -> t m b -> t m b -- | Schedule the execution of two streams in a fair round-robin manner, -- executing each stream once, alternately. Execution of a stream may not -- necessarily result in an output, a stream may chose to Skip -- producing an element until later giving the other stream a chance to -- run. Therefore, this combinator fairly interleaves the execution of -- two streams rather than fairly interleaving the output of the two -- streams. This can be useful in co-operative multitasking without using -- explicit threads. This can be used as an alternative to async. -- -- Do not use at scale in concatMapWith. -- -- Pre-release roundrobin :: (IsStream t, Monad m) => t m b -> t m b -> t m b -- | Stream a is evaluated first, followed by stream b, -- the resulting elements a and b are then zipped using -- the supplied zip function and the result c is yielded to the -- consumer. -- -- If stream a or stream b ends, the zipped stream -- ends. If stream b ends first, the element a from -- previous evaluation of stream a is discarded. -- --
-- > D.toList $ D.zipWith (+) (D.fromList [1,2,3]) (D.fromList [4,5,6]) -- [5,7,9] --zipWith :: (IsStream t, Monad m) => (a -> b -> c) -> t m a -> t m b -> t m c -- | Like zipWith but using a monadic zipping function. zipWithM :: (IsStream t, Monad m) => (a -> b -> m c) -> t m a -> t m b -> t m c -- | Like zipWith but zips concurrently i.e. both the streams being -- zipped are evaluated concurrently using the ParallelT -- concurrent evaluation style. The maximum number of elements of each -- stream evaluated in advance can be controlled by maxBuffer. -- -- The stream ends if stream a or stream b ends. -- However, if stream b ends while we are still evaluating -- stream a and waiting for a result then stream will not end -- until after the evaluation of stream a finishes. This -- behavior can potentially be changed in future to end the stream -- immediately as soon as any of the stream end is detected. zipAsyncWith :: (IsStream t, MonadAsync m) => (a -> b -> c) -> t m a -> t m b -> t m c -- | Like zipAsyncWith but with a monadic zipping function. zipAsyncWithM :: (IsStream t, MonadAsync m) => (a -> b -> m c) -> t m a -> t m b -> t m c -- | Same as mergeBy compare. -- --
-- >>> Stream.toList $ Stream.merge (Stream.fromList [1,3,5]) (Stream.fromList [2,4,6,8]) -- [1,2,3,4,5,6,8] ---- -- Internal merge :: (IsStream t, Ord a) => t m a -> t m a -> t m a -- | Merge two streams using a comparison function. The head elements of -- both the streams are compared and the smaller of the two elements is -- emitted, if both elements are equal then the element from the first -- stream is used first. -- -- If the streams are sorted in ascending order, the resulting stream -- would also remain sorted in ascending order. -- --
-- >>> Stream.toList $ Stream.mergeBy compare (Stream.fromList [1,3,5]) (Stream.fromList [2,4,6,8]) -- [1,2,3,4,5,6,8] ---- -- See also: mergeByMFused mergeBy :: IsStream t => (a -> a -> Ordering) -> t m a -> t m a -> t m a -- | Like mergeBy but with a monadic comparison function. -- -- Merge two streams randomly: -- --
-- > randomly _ _ = randomIO >>= x -> return $ if x then LT else GT -- > Stream.toList $ Stream.mergeByM randomly (Stream.fromList [1,1,1,1]) (Stream.fromList [2,2,2,2]) -- [2,1,2,2,2,1,1,1] ---- -- Merge two streams in a proportion of 2:1: -- --
-- >>> :{ -- do -- let proportionately m n = do -- ref <- newIORef $ cycle $ Prelude.concat [Prelude.replicate m LT, Prelude.replicate n GT] -- return $ _ _ -> do -- r <- readIORef ref -- writeIORef ref $ Prelude.tail r -- return $ Prelude.head r -- f <- proportionately 2 1 -- xs <- Stream.toList $ Stream.mergeByM f (Stream.fromList [1,1,1,1,1,1]) (Stream.fromList [2,2,2]) -- print xs -- :} -- [1,1,2,1,1,2,1,1,2] ---- -- See also: mergeByMFused mergeByM :: (IsStream t, Monad m) => (a -> a -> m Ordering) -> t m a -> t m a -> t m a -- | Like mergeByM but much faster, works best when merging -- statically known number of streams. When merging more than two streams -- try to merge pairs and pair pf pairs in a tree like -- structure.mergeByM works better with variable number of streams -- being merged using concatPairsWith. -- -- Internal mergeByMFused :: (IsStream t, Monad m) => (a -> a -> m Ordering) -> t m a -> t m a -> t m a -- | Like mergeBy but merges concurrently (i.e. both the elements -- being merged are generated concurrently). mergeAsyncBy :: (IsStream t, MonadAsync m) => (a -> a -> Ordering) -> t m a -> t m a -> t m a -- | Like mergeByM but merges concurrently (i.e. both the elements -- being merged are generated concurrently). mergeAsyncByM :: (IsStream t, MonadAsync m) => (a -> a -> m Ordering) -> t m a -> t m a -> t m a -- | Like mergeByM but stops merging as soon as any of the two -- streams stops. -- -- Unimplemented mergeMinBy :: (a -> a -> m Ordering) -> t m a -> t m a -> t m a -- | Like mergeByM but stops merging as soon as the first stream -- stops. -- -- Unimplemented mergeFstBy :: (a -> a -> m Ordering) -> t m a -> t m a -> t m a -- | Like concatMap but uses an Unfold for stream generation. -- Unlike concatMap this can fuse the Unfold code with the -- inner loop and therefore provide many times better performance. unfoldMany :: (IsStream t, Monad m) => Unfold m a b -> t m a -> t m b -- | Like unfoldMany but interleaves the streams in the same way as -- interleave behaves instead of appending them. -- -- Pre-release unfoldManyInterleave :: (IsStream t, Monad m) => Unfold m a b -> t m a -> t m b -- | Like unfoldMany but executes the streams in the same way as -- roundrobin. -- -- Pre-release unfoldManyRoundRobin :: (IsStream t, Monad m) => Unfold m a b -> t m a -> t m b -- | Unfold the elements of a stream, intersperse the given element between -- the unfolded streams and then concat them into a single stream. -- --
-- unwords = S.interpose ' ' ---- -- Pre-release interpose :: (IsStream t, Monad m) => c -> Unfold m b c -> t m b -> t m c -- | Unfold the elements of a stream, append the given element after each -- unfolded stream and then concat them into a single stream. -- --
-- unlines = S.interposeSuffix '\n' ---- -- Pre-release interposeSuffix :: (IsStream t, Monad m) => c -> Unfold m b c -> t m b -> t m c -- | intersperse followed by unfold and concat. -- --
-- intercalate unf a str = unfoldMany unf $ intersperse a str -- intersperse = intercalate (Unfold.function id) -- unwords = intercalate Unfold.fromList " " ---- --
-- >>> Stream.toList $ Stream.intercalate Unfold.fromList " " $ Stream.fromList ["abc", "def", "ghi"] -- "abc def ghi" --intercalate :: (IsStream t, Monad m) => Unfold m b c -> b -> t m b -> t m c -- | intersperseMSuffix followed by unfold and concat. -- --
-- intercalateSuffix unf a str = unfoldMany unf $ intersperseMSuffix a str -- intersperseMSuffix = intercalateSuffix (Unfold.function id) -- unlines = intercalateSuffix Unfold.fromList "\n" ---- --
-- >>> Stream.toList $ Stream.intercalateSuffix Unfold.fromList "\n" $ Stream.fromList ["abc", "def", "ghi"] -- "abc\ndef\nghi\n" --intercalateSuffix :: (IsStream t, Monad m) => Unfold m b c -> b -> t m b -> t m c -- | interleaveInfix followed by unfold and concat. -- -- Pre-release gintercalate :: (IsStream t, Monad m) => Unfold m a c -> t m a -> Unfold m b c -> t m b -> t m c -- | interleaveSuffix followed by unfold and concat. -- -- Pre-release gintercalateSuffix :: (IsStream t, Monad m) => Unfold m a c -> t m a -> Unfold m b c -> t m b -> t m c -- | Map a stream producing monadic function on each element of the stream -- and then flatten the results into a single stream. Since the stream -- generation function is monadic, unlike concatMap, it can -- produce an effect at the beginning of each iteration of the inner -- loop. concatMapM :: (IsStream t, Monad m) => (a -> m (t m b)) -> t m a -> t m b -- | Map a stream producing function on each element of the stream and then -- flatten the results into a single stream. -- --
-- >>> concatMap f = Stream.concatMapM (return . f) -- -- >>> concatMap f = Stream.concatMapWith Stream.serial f -- -- >>> concatMap f = Stream.concat . Stream.map f --concatMap :: (IsStream t, Monad m) => (a -> t m b) -> t m a -> t m b -- | Given a stream value in the underlying monad, lift and join the -- underlying monad with the stream monad. -- --
-- >>> concatM = Stream.concat . Stream.fromEffect -- -- >>> concatM = Stream.concat . lift -- requires (MonadTrans t) -- -- >>> concatM = join . lift -- requires (MonadTrans t, Monad (t m)) ---- -- See also: concat, sequence -- -- Internal concatM :: (IsStream t, Monad m) => m (t m a) -> t m a -- | Flatten a stream of streams to a single stream. -- --
-- concat = concatMap id ---- -- Pre-release concat :: (IsStream t, Monad m) => t m (t m a) -> t m a -- | A variant of fold that allows you to fold a Foldable -- container of streams using the specified stream sum operation. -- --
-- concatFoldableWith async $ map return [1..3] ---- -- Equivalent to: -- --
-- concatFoldableWith f = Prelude.foldr f D.nil -- concatFoldableWith f = D.concatMapFoldableWith f id ---- -- Since: 0.8.0 (Renamed foldWith to concatFoldableWith) -- -- Since: 0.1.0 (Streamly) concatFoldableWith :: (IsStream t, Foldable f) => (t m a -> t m a -> t m a) -> f (t m a) -> t m a -- | A variant of foldMap that allows you to map a monadic -- streaming action on a Foldable container and then fold it using -- the specified stream merge operation. -- --
-- concatMapFoldableWith async return [1..3] ---- -- Equivalent to: -- --
-- concatMapFoldableWith f g = Prelude.foldr (f . g) S.nil -- concatMapFoldableWith f g xs = S.concatMapWith f g (S.fromFoldable xs) ---- -- Since: 0.8.0 (Renamed foldMapWith to concatMapFoldableWith) -- -- Since: 0.1.0 (Streamly) concatMapFoldableWith :: (IsStream t, Foldable f) => (t m b -> t m b -> t m b) -> (a -> t m b) -> f a -> t m b -- | Like concatMapFoldableWith but with the last two arguments -- reversed i.e. the monadic streaming function is the last argument. -- -- Equivalent to: -- --
-- concatForFoldableWith f xs g = Prelude.foldr (f . g) D.nil xs -- concatForFoldableWith f = flip (D.concatMapFoldableWith f) ---- -- Since: 0.8.0 (Renamed forEachWith to concatForFoldableWith) -- -- Since: 0.1.0 (Streamly) concatForFoldableWith :: (IsStream t, Foldable f) => (t m b -> t m b -> t m b) -> f a -> (a -> t m b) -> t m b -- | concatMapWith mixer generator stream is a two dimensional -- looping combinator. The generator function is used to -- generate streams from the elements in the input stream and -- the mixer function is used to merge those streams. -- -- Note we can merge streams concurrently by using a concurrent merge -- function. -- -- Since: 0.7.0 -- -- Since: 0.8.0 (signature change) concatMapWith :: IsStream t => (t m b -> t m b -> t m b) -> (a -> t m b) -> t m a -> t m b bindWith :: IsStream t => (t m b -> t m b -> t m b) -> t m a -> (a -> t m b) -> t m b -- | Like concatMapWith but carries a state which can be used to -- share information across multiple steps of concat. -- --
-- concatSmapMWith combine f initial = concatMapWith combine id . smapM f initial ---- -- Pre-release concatSmapMWith :: (IsStream t, Monad m) => (t m b -> t m b -> t m b) -> (s -> a -> m (s, t m b)) -> m s -> t m a -> t m b -- | Combine streams in pairs using a binary stream combinator, then -- combine the resulting streams in pairs recursively until we get to a -- single combined stream. -- -- For example, you can sort a stream using merge sort like this: -- --
-- >>> Stream.toList $ Stream.concatPairsWith (Stream.mergeBy compare) Stream.fromPure $ Stream.fromList [5,1,7,9,2] -- [1,2,5,7,9] ---- -- Caution: the stream of streams must be finite -- -- Pre-release concatPairsWith :: IsStream t => (t m b -> t m b -> t m b) -> (a -> t m b) -> t m a -> t m b -- | Like iterateM but iterates after mapping a stream generator -- on the output. -- -- Yield an input element in the output stream, map a stream generator on -- it and then do the same on the resulting stream. This can be used for -- a depth first traversal of a tree like structure. -- -- Note that iterateM is a special case of -- iterateMapWith: -- --
-- iterateM f = iterateMapWith serial (fromEffect . f) . fromEffect ---- -- It can be used to traverse a tree structure. For example, to list a -- directory tree: -- --
-- Stream.iterateMapWith Stream.serial -- (either Dir.toEither (const nil)) -- (fromPure (Left "tmp")) ---- -- Pre-release iterateMapWith :: IsStream t => (t m a -> t m a -> t m a) -> (a -> t m a) -> t m a -> t m a -- | Like iterateMap but carries a state in the stream generation -- function. This can be used to traverse graph like structures, we can -- remember the visited nodes in the state to avoid cycles. -- -- Note that a combination of iterateMap and usingState -- can also be used to traverse graphs. However, this function provides a -- more localized state instead of using a global state. -- -- See also: mfix -- -- Pre-release iterateSmapMWith :: (IsStream t, Monad m) => (t m a -> t m a -> t m a) -> (b -> a -> m (b, t m a)) -> m b -> t m a -> t m a -- | In an Either stream iterate on Lefts. This is a special -- case of iterateMapWith: -- --
-- iterateMapLeftsWith combine f = iterateMapWith combine (either f (const nil)) ---- -- To traverse a directory tree: -- --
-- iterateMapLeftsWith serial Dir.toEither (fromPure (Left "tmp")) ---- -- Pre-release iterateMapLeftsWith :: (IsStream t, b ~ Either a c) => (t m b -> t m b -> t m b) -> (a -> t m b) -> t m b -> t m b -- | Same as iterateMapWith Stream.serial but more efficient due -- to stream fusion. -- -- Unimplemented iterateUnfold :: Unfold m a a -> t m a -> t m a concatUnfold :: (IsStream t, Monad m) => Unfold m a b -> t m a -> t m b -- | Drop prefix from the input stream if present. -- -- Space: O(1) -- -- Unimplemented dropPrefix :: t m a -> t m a -> t m a -- | Drop all matching infix from the input stream if present. Infix stream -- may be consumed multiple times. -- -- Space: O(n) where n is the length of the infix. -- -- Unimplemented dropInfix :: t m a -> t m a -> t m a -- | Drop suffix from the input stream if present. Suffix stream may be -- consumed multiple times. -- -- Space: O(n) where n is the length of the suffix. -- -- Unimplemented dropSuffix :: t m a -> t m a -> t m a -- | Apply a Fold repeatedly on a stream and emit the fold outputs -- in the output stream. -- -- To sum every two contiguous elements in a stream: -- --
-- >>> f = Fold.take 2 Fold.sum -- -- >>> Stream.toList $ Stream.foldMany f $ Stream.fromList [1..10] -- [3,7,11,15,19] ---- -- On an empty stream the output is empty: -- --
-- >>> Stream.toList $ Stream.foldMany f $ Stream.fromList [] -- [] ---- -- Note Stream.foldMany (Fold.take 0) would result in an -- infinite loop in a non-empty stream. foldMany :: (IsStream t, Monad m) => Fold m a b -> t m a -> t m b -- | Like foldMany but appends empty fold output if the fold and -- stream termination aligns: -- --
-- >>> f = Fold.take 2 Fold.sum -- -- >>> Stream.toList $ Stream.foldManyPost f $ Stream.fromList [] -- [0] -- -- >>> Stream.toList $ Stream.foldManyPost f $ Stream.fromList [1..9] -- [3,7,11,15,9] -- -- >>> Stream.toList $ Stream.foldManyPost f $ Stream.fromList [1..10] -- [3,7,11,15,19,0] ---- -- Pre-release foldManyPost :: (IsStream t, Monad m) => Fold m a b -> t m a -> t m b -- | Like foldMany but using the Refold type instead of -- Fold. -- -- Pre-release refoldMany :: (IsStream t, Monad m) => Refold m c a b -> m c -> t m a -> t m b -- | Apply a stream of folds to an input stream and emit the results in the -- output stream. -- -- Unimplemented foldSequence :: t m (Fold m a b) -> t m a -> t m b -- | Iterate a fold generator on a stream. The initial value b is -- used to generate the first fold, the fold is applied on the stream and -- the result of the fold is used to generate the next fold and so on. -- --
-- >>> import Data.Monoid (Sum(..)) -- >>> f x = return (Fold.take 2 (Fold.sconcat x)) -- >>> s = Stream.map Sum $ Stream.fromList [1..10] -- >>> Stream.toList $ Stream.map getSum $ Stream.foldIterateM f (pure 0) s -- [3,10,21,36,55,55] ---- -- This is the streaming equivalent of monad like sequenced application -- of folds where next fold is dependent on the previous fold. -- -- Pre-release foldIterateM :: (IsStream t, Monad m) => (b -> m (Fold m a b)) -> m b -> t m a -> t m b -- | Like foldIterateM but using the Refold type instead. -- This could be much more efficient due to stream fusion. -- -- Internal refoldIterateM :: (IsStream t, Monad m) => Refold m b a b -> m b -> t m a -> t m b -- | Group the input stream into groups of n elements each and -- then fold each group using the provided fold function. -- --
-- >>> Stream.toList $ Stream.chunksOf 2 Fold.sum (Stream.enumerateFromTo 1 10) -- [3,7,11,15,19] ---- -- This can be considered as an n-fold version of take where we -- apply take repeatedly on the leftover stream until the stream -- exhausts. -- --
-- chunksOf n f = foldMany (FL.take n f) --chunksOf :: (IsStream t, Monad m) => Int -> Fold m a b -> t m a -> t m b -- | arraysOf n stream groups the elements in the input stream -- into arrays of n elements each. -- -- Same as the following but may be more efficient: -- --
-- arraysOf n = Stream.foldMany (A.writeN n) ---- -- Pre-release arraysOf :: (IsStream t, MonadIO m, Unbox a) => Int -> t m a -> t m (Array a) -- | Group the input stream into windows of n second each and then -- fold each group using the provided fold function. -- --
-- >>> Stream.toList $ Stream.take 5 $ Stream.intervalsOf 1 Fold.sum $ Stream.constRate 2 $ Stream.enumerateFrom 1 -- [...,...,...,...,...] --intervalsOf :: (IsStream t, MonadAsync m) => Double -> Fold m a b -> t m a -> t m b -- | Like chunksOf but if the chunk is not completed within the -- specified time interval then emit whatever we have collected till now. -- The chunk timeout is reset whenever a chunk is emitted. The -- granularity of the clock is 100 ms. -- --
-- >>> s = Stream.delayPost 0.3 $ Stream.fromList [1..1000] -- -- >>> f = Stream.mapM_ print $ Stream.chunksOfTimeout 5 1 Fold.toList s ---- -- Pre-release chunksOfTimeout :: (IsStream t, MonadAsync m, Functor (t m)) => Int -> Double -> Fold m a b -> t m a -> t m b -- | Split on an infixed separator element, dropping the separator. The -- supplied Fold is applied on the split segments. Splits the -- stream on separator elements determined by the supplied predicate, -- separator is considered as infixed between two segments: -- --
-- >>> splitOn' p xs = Stream.toList $ Stream.splitOn p Fold.toList (Stream.fromList xs) -- -- >>> splitOn' (== '.') "a.b" -- ["a","b"] ---- -- An empty stream is folded to the default value of the fold: -- --
-- >>> splitOn' (== '.') "" -- [""] ---- -- If one or both sides of the separator are missing then the empty -- segment on that side is folded to the default output of the fold: -- --
-- >>> splitOn' (== '.') "." -- ["",""] ---- --
-- >>> splitOn' (== '.') ".a" -- ["","a"] ---- --
-- >>> splitOn' (== '.') "a." -- ["a",""] ---- --
-- >>> splitOn' (== '.') "a..b" -- ["a","","b"] ---- -- splitOn is an inverse of intercalating single element: -- --
-- Stream.intercalate (Stream.fromPure '.') Unfold.fromList . Stream.splitOn (== '.') Fold.toList === id ---- -- Assuming the input stream does not contain the separator: -- --
-- Stream.splitOn (== '.') Fold.toList . Stream.intercalate (Stream.fromPure '.') Unfold.fromList === id --splitOn :: (IsStream t, Monad m) => (a -> Bool) -> Fold m a b -> t m a -> t m b -- | Split on a suffixed separator element, dropping the separator. The -- supplied Fold is applied on the split segments. -- --
-- >>> splitOnSuffix' p xs = Stream.toList $ Stream.splitOnSuffix p Fold.toList (Stream.fromList xs) -- -- >>> splitOnSuffix' (== '.') "a.b." -- ["a","b"] ---- --
-- >>> splitOnSuffix' (== '.') "a." -- ["a"] ---- -- An empty stream results in an empty output stream: -- --
-- >>> splitOnSuffix' (== '.') "" -- [] ---- -- An empty segment consisting of only a suffix is folded to the default -- output of the fold: -- --
-- >>> splitOnSuffix' (== '.') "." -- [""] ---- --
-- >>> splitOnSuffix' (== '.') "a..b.." -- ["a","","b",""] ---- -- A suffix is optional at the end of the stream: -- --
-- >>> splitOnSuffix' (== '.') "a" -- ["a"] ---- --
-- >>> splitOnSuffix' (== '.') ".a" -- ["","a"] ---- --
-- >>> splitOnSuffix' (== '.') "a.b" -- ["a","b"] ---- --
-- lines = splitOnSuffix (== '\n') ---- -- splitOnSuffix is an inverse of intercalateSuffix with -- a single element: -- --
-- Stream.intercalateSuffix (Stream.fromPure '.') Unfold.fromList . Stream.splitOnSuffix (== '.') Fold.toList === id ---- -- Assuming the input stream does not contain the separator: -- --
-- Stream.splitOnSuffix (== '.') Fold.toList . Stream.intercalateSuffix (Stream.fromPure '.') Unfold.fromList === id --splitOnSuffix :: (IsStream t, Monad m) => (a -> Bool) -> Fold m a b -> t m a -> t m b -- | Split on a prefixed separator element, dropping the separator. The -- supplied Fold is applied on the split segments. -- --
-- > splitOnPrefix' p xs = Stream.toList $ Stream.splitOnPrefix p (Fold.toList) (Stream.fromList xs) -- > splitOnPrefix' (== .) ".a.b" -- ["a","b"] ---- -- An empty stream results in an empty output stream: > -- splitOnPrefix' (== .) "" [] -- -- An empty segment consisting of only a prefix is folded to the default -- output of the fold: -- --
-- > splitOnPrefix' (== .) "." -- [""] -- -- > splitOnPrefix' (== .) ".a.b." -- ["a","b",""] -- -- > splitOnPrefix' (== .) ".a..b" -- ["a","","b"] ---- -- A prefix is optional at the beginning of the stream: -- --
-- > splitOnPrefix' (== .) "a" -- ["a"] -- -- > splitOnPrefix' (== .) "a.b" -- ["a","b"] ---- -- splitOnPrefix is an inverse of intercalatePrefix with -- a single element: -- --
-- Stream.intercalatePrefix (Stream.fromPure '.') Unfold.fromList . Stream.splitOnPrefix (== '.') Fold.toList === id ---- -- Assuming the input stream does not contain the separator: -- --
-- Stream.splitOnPrefix (== '.') Fold.toList . Stream.intercalatePrefix (Stream.fromPure '.') Unfold.fromList === id ---- -- Unimplemented splitOnPrefix :: (a -> Bool) -> Fold m a b -> t m a -> t m b -- | Split on any one of the given patterns. -- -- Unimplemented splitOnAny :: [Array a] -> Fold m a b -> t m a -> t m b -- | Like splitOnSuffix but keeps the suffix attached to the -- resulting splits. -- --
-- >>> splitWithSuffix' p xs = Stream.toList $ splitWithSuffix p Fold.toList (Stream.fromList xs) ---- --
-- >>> splitWithSuffix' (== '.') "" -- [] ---- --
-- >>> splitWithSuffix' (== '.') "." -- ["."] ---- --
-- >>> splitWithSuffix' (== '.') "a" -- ["a"] ---- --
-- >>> splitWithSuffix' (== '.') ".a" -- [".","a"] ---- --
-- >>> splitWithSuffix' (== '.') "a." -- ["a."] ---- --
-- >>> splitWithSuffix' (== '.') "a.b" -- ["a.","b"] ---- --
-- >>> splitWithSuffix' (== '.') "a.b." -- ["a.","b."] ---- --
-- >>> splitWithSuffix' (== '.') "a..b.." -- ["a.",".","b.","."] --splitWithSuffix :: (IsStream t, Monad m) => (a -> Bool) -> Fold m a b -> t m a -> t m b -- | Like splitOnSeq but splits the separator as well, as an infix -- token. -- --
-- >>> splitOn'_ pat xs = Stream.toList $ Stream.splitBySeq (Array.fromList pat) Fold.toList (Stream.fromList xs) ---- --
-- >>> splitOn'_ "" "hello" -- ["h","","e","","l","","l","","o"] ---- --
-- >>> splitOn'_ "hello" "" -- [""] ---- --
-- >>> splitOn'_ "hello" "hello" -- ["","hello",""] ---- --
-- >>> splitOn'_ "x" "hello" -- ["hello"] ---- --
-- >>> splitOn'_ "h" "hello" -- ["","h","ello"] ---- --
-- >>> splitOn'_ "o" "hello" -- ["hell","o",""] ---- --
-- >>> splitOn'_ "e" "hello" -- ["h","e","llo"] ---- --
-- >>> splitOn'_ "l" "hello" -- ["he","l","","l","o"] ---- --
-- >>> splitOn'_ "ll" "hello" -- ["he","ll","o"] ---- -- Pre-release splitBySeq :: (IsStream t, MonadAsync m, Storable a, Unbox a, Enum a, Eq a) => Array a -> Fold m a b -> t m a -> t m b -- | Like splitOn but the separator is a sequence of elements -- instead of a single element. -- -- For illustration, let's define a function that operates on pure lists: -- --
-- >>> splitOnSeq' pat xs = Stream.toList $ Stream.splitOnSeq (Array.fromList pat) Fold.toList (Stream.fromList xs) ---- --
-- >>> splitOnSeq' "" "hello" -- ["h","e","l","l","o"] ---- --
-- >>> splitOnSeq' "hello" "" -- [""] ---- --
-- >>> splitOnSeq' "hello" "hello" -- ["",""] ---- --
-- >>> splitOnSeq' "x" "hello" -- ["hello"] ---- --
-- >>> splitOnSeq' "h" "hello" -- ["","ello"] ---- --
-- >>> splitOnSeq' "o" "hello" -- ["hell",""] ---- --
-- >>> splitOnSeq' "e" "hello" -- ["h","llo"] ---- --
-- >>> splitOnSeq' "l" "hello" -- ["he","","o"] ---- --
-- >>> splitOnSeq' "ll" "hello" -- ["he","o"] ---- -- splitOnSeq is an inverse of intercalate. The following -- law always holds: -- --
-- intercalate . splitOnSeq == id ---- -- The following law holds when the separator is non-empty and contains -- none of the elements present in the input lists: -- --
-- splitOnSeq . intercalate == id ---- --
-- >>> splitOnSeq pat f = Stream.foldManyPost (Fold.takeEndBySeq_ pat f) ---- -- Pre-release splitOnSeq :: (IsStream t, MonadIO m, Storable a, Unbox a, Enum a, Eq a) => Array a -> Fold m a b -> t m a -> t m b -- | Like splitSuffixBy but the separator is a sequence of -- elements, instead of a predicate for a single element. -- --
-- >>> splitOnSuffixSeq_ pat xs = Stream.toList $ Stream.splitOnSuffixSeq (Array.fromList pat) Fold.toList (Stream.fromList xs) ---- --
-- >>> splitOnSuffixSeq_ "." "" -- [] ---- --
-- >>> splitOnSuffixSeq_ "." "." -- [""] ---- --
-- >>> splitOnSuffixSeq_ "." "a" -- ["a"] ---- --
-- >>> splitOnSuffixSeq_ "." ".a" -- ["","a"] ---- --
-- >>> splitOnSuffixSeq_ "." "a." -- ["a"] ---- --
-- >>> splitOnSuffixSeq_ "." "a.b" -- ["a","b"] ---- --
-- >>> splitOnSuffixSeq_ "." "a.b." -- ["a","b"] ---- --
-- >>> splitOnSuffixSeq_ "." "a..b.." -- ["a","","b",""] ---- --
-- lines = splitOnSuffixSeq "\n" ---- -- splitOnSuffixSeq is an inverse of intercalateSuffix. -- The following law always holds: -- --
-- intercalateSuffix . splitOnSuffixSeq == id ---- -- The following law holds when the separator is non-empty and contains -- none of the elements present in the input lists: -- --
-- splitSuffixOn . intercalateSuffix == id ---- --
-- >>> splitOnSuffixSeq pat f = Stream.foldMany (Fold.takeEndBySeq_ pat f) ---- -- Pre-release splitOnSuffixSeq :: (IsStream t, MonadIO m, Storable a, Unbox a, Enum a, Eq a) => Array a -> Fold m a b -> t m a -> t m b -- | Like splitOnSuffixSeq but keeps the suffix intact in the -- splits. -- --
-- >>> splitWithSuffixSeq' pat xs = Stream.toList $ Stream.splitWithSuffixSeq (Array.fromList pat) Fold.toList (Stream.fromList xs) ---- --
-- >>> splitWithSuffixSeq' "." "" -- [] ---- --
-- >>> splitWithSuffixSeq' "." "." -- ["."] ---- --
-- >>> splitWithSuffixSeq' "." "a" -- ["a"] ---- --
-- >>> splitWithSuffixSeq' "." ".a" -- [".","a"] ---- --
-- >>> splitWithSuffixSeq' "." "a." -- ["a."] ---- --
-- >>> splitWithSuffixSeq' "." "a.b" -- ["a.","b"] ---- --
-- >>> splitWithSuffixSeq' "." "a.b." -- ["a.","b."] ---- --
-- >>> splitWithSuffixSeq' "." "a..b.." -- ["a.",".","b.","."] ---- --
-- >>> splitWithSuffixSeq pat f = Stream.foldMany (Fold.takeEndBySeq pat f) ---- -- Pre-release splitWithSuffixSeq :: (IsStream t, MonadIO m, Storable a, Unbox a, Enum a, Eq a) => Array a -> Fold m a b -> t m a -> t m b -- | Split post any one of the given patterns. -- -- Unimplemented splitOnSuffixSeqAny :: [Array a] -> Fold m a b -> t m a -> t m b classifySessionsByGeneric :: forall t m f a b. (IsStream t, MonadAsync m, IsMap f) => Proxy (f :: Type -> Type) -> Double -> Bool -> (Int -> m Bool) -> Double -> Fold m a b -> t m (AbsTime, (Key f, a)) -> t m (Key f, b) -- | classifySessionsBy tick keepalive predicate timeout fold -- stream classifies an input event stream consisting of -- (timestamp, (key, value)) into sessions based on the -- key, folding all the values corresponding to the same key -- into a session using the supplied fold. -- -- When the fold terminates or a timeout occurs, a tuple -- consisting of the session key and the folded value is emitted in the -- output stream. The timeout is measured from the first event in the -- session. If the keepalive option is set to True the -- timeout is reset to 0 whenever an event is received. -- -- The timestamp in the input stream is an absolute time from -- some epoch, characterizing the time when the input event was -- generated. The notion of current time is maintained by a monotonic -- event time clock using the timestamps seen in the input stream. The -- latest timestamp seen till now is used as the base for the current -- time. When no new events are seen, a timer is started with a clock -- resolution of tick seconds. This timer is used to detect -- session timeouts in the absence of new events. -- -- To ensure an upper bound on the memory used the number of sessions can -- be limited to an upper bound. If the ejection predicate -- returns True, the oldest session is ejected before inserting a -- new session. -- -- When the stream ends any buffered sessions are ejected immediately. -- -- If a session key is received even after a session has finished, -- another session is created for that key. -- --
-- >>> :{ -- Stream.mapM_ print -- $ Stream.classifySessionsBy 1 False (const (return False)) 3 (Fold.take 3 Fold.toList) -- $ Stream.timestamped -- $ Stream.delay 0.1 -- $ Stream.fromList ((,) <$> [1,2,3] <*> ['a','b','c']) -- :} -- (1,"abc") -- (2,"abc") -- (3,"abc") ---- -- Pre-release classifySessionsBy :: (IsStream t, MonadAsync m, Ord k) => Double -> Bool -> (Int -> m Bool) -> Double -> Fold m a b -> t m (AbsTime, (k, a)) -> t m (k, b) -- | Same as classifySessionsBy with a timer tick of 1 second and -- keepalive option set to False. -- --
-- classifySessionsOf = classifySessionsBy 1 False ---- -- Pre-release classifySessionsOf :: (IsStream t, MonadAsync m, Ord k) => (Int -> m Bool) -> Double -> Fold m a b -> t m (AbsTime, (k, a)) -> t m (k, b) -- | Same as classifySessionsBy with a timer tick of 1 second and -- keepalive option set to True. -- --
-- classifyKeepAliveSessions = classifySessionsBy 1 True ---- -- Pre-release classifyKeepAliveSessions :: (IsStream t, MonadAsync m, Ord k) => (Int -> m Bool) -> Double -> Fold m a b -> t m (AbsTime, (k, a)) -> t m (k, b) -- | Apply a Parser repeatedly on a stream and emit the parsed -- values in the output stream. -- -- This is the streaming equivalent of the many parse combinator. -- --
-- >>> Stream.toList $ Stream.parseMany (Parser.takeBetween 0 2 Fold.sum) $ Stream.fromList [1..10] -- [Right 3,Right 7,Right 11,Right 15,Right 19] ---- --
-- > Stream.toList $ Stream.parseMany (Parser.line Fold.toList) $ Stream.fromList "hello\nworld" -- ["hello\n","world"] ---- --
-- foldMany f = parseMany (fromFold f) ---- -- Known Issues: When the parser fails there is no way to get the -- remaining stream. -- -- Pre-release parseMany :: (IsStream t, Monad m) => Parser a m b -> t m a -> t m (Either ParseError b) -- | Same as parseMany but for StreamD streams. -- -- Internal parseManyD :: (IsStream t, Monad m) => Parser a m b -> t m a -> t m (Either ParseError b) -- | parseManyTill collect test stream tries the parser -- test on the input, if test fails it backtracks and -- tries collect, after collect succeeds test -- is tried again and so on. The parser stops when test -- succeeds. The output of test is discarded and the output of -- collect is emitted in the output stream. The parser fails if -- collect fails. -- -- Unimplemented parseManyTill :: Parser a m b -> Parser a m x -> t m a -> t m b -- | Apply a stream of parsers to an input stream and emit the results in -- the output stream. -- -- Unimplemented parseSequence :: t m (Parser a m b) -> t m a -> t m b -- | Iterate a parser generating function on a stream. The initial value -- b is used to generate the first parser, the parser is applied -- on the stream and the result is used to generate the next parser and -- so on. -- --
-- >>> import Data.Monoid (Sum(..)) -- -- >>> Stream.toList $ fmap getSum $ Stream.rights $ Stream.parseIterate (\b -> Parser.takeBetween 0 2 (Fold.sconcat b)) (Sum 0) $ fmap Sum $ Stream.fromList [1..10] -- [3,10,21,36,55,55] ---- -- This is the streaming equivalent of monad like sequenced application -- of parsers where next parser is dependent on the previous parser. -- -- Pre-release parseIterate :: (IsStream t, Monad m) => (b -> Parser a m b) -> b -> t m a -> t m (Either ParseError b) -- | Like splitOn after stripping leading, trailing, and repeated -- separators. Therefore, ".a..b." with . as the -- separator would be parsed as ["a","b"]. In other words, its -- like parsing words from whitespace separated text. -- --
-- >>> wordsBy' p xs = Stream.toList $ Stream.wordsBy p Fold.toList (Stream.fromList xs) ---- --
-- >>> wordsBy' (== ',') "" -- [] ---- --
-- >>> wordsBy' (== ',') "," -- [] ---- --
-- >>> wordsBy' (== ',') ",a,,b," -- ["a","b"] ---- --
-- words = wordsBy isSpace --wordsBy :: (IsStream t, Monad m) => (a -> Bool) -> Fold m a b -> t m a -> t m b -- | Like splitOn but drops any empty splits. -- -- Unimplemented wordsOn :: Array a -> Fold m a b -> t m a -> t m b -- |
-- groups = groupsBy (==) -- groups = groupsByRolling (==) ---- -- Groups contiguous spans of equal elements together in individual -- groups. -- --
-- >>> Stream.toList $ Stream.groups Fold.toList $ Stream.fromList [1,1,2,2] -- [[1,1],[2,2]] --groups :: (IsStream t, Monad m, Eq a) => Fold m a b -> t m a -> t m b -- | groupsBy cmp f $ S.fromList [a,b,c,...] assigns the element -- a to the first group, if b `cmp` a is True -- then b is also assigned to the same group. If c `cmp` -- a is True then c is also assigned to the same -- group and so on. When the comparison fails a new group is started. -- Each group is folded using the fold f and the result of the -- fold is emitted in the output stream. -- --
-- >>> Stream.toList $ Stream.groupsBy (>) Fold.toList $ Stream.fromList [1,3,7,0,2,5] -- [[1,3,7],[0,2,5]] --groupsBy :: (IsStream t, Monad m) => (a -> a -> Bool) -> Fold m a b -> t m a -> t m b -- | Unlike groupsBy this function performs a rolling comparison -- of two successive elements in the input stream. groupsByRolling -- cmp f $ S.fromList [a,b,c,...] assigns the element a to -- the first group, if a `cmp` b is True then b -- is also assigned to the same group. If b `cmp` c is -- True then c is also assigned to the same group and so -- on. When the comparison fails a new group is started. Each group is -- folded using the fold f. -- --
-- >>> Stream.toList $ Stream.groupsByRolling (\a b -> a + 1 == b) Fold.toList $ Stream.fromList [1,2,3,7,8,9] -- [[1,2,3],[7,8,9]] --groupsByRolling :: (IsStream t, Monad m) => (a -> a -> Bool) -> Fold m a b -> t m a -> t m b -- | splitInnerBy splitter joiner stream splits the inner -- containers f a of an input stream t m (f a) using -- the splitter function. Container elements f a are -- collected until a split occurs, then all the elements before the split -- are joined using the joiner function. -- -- For example, if we have a stream of Array Word8, we may want -- to split the stream into arrays representing lines separated by 'n' -- byte such that the resulting stream after a split would be one array -- for each line. -- -- CAUTION! This is not a true streaming function as the container size -- after the split and merge may not be bounded. -- -- Pre-release splitInnerBy :: (IsStream t, Monad m) => (f a -> m (f a, Maybe (f a))) -> (f a -> f a -> m (f a)) -> t m (f a) -> t m (f a) -- | Like splitInnerBy but splits assuming the separator joins the -- segment in a suffix style. -- -- Pre-release splitInnerBySuffix :: (IsStream t, Monad m, Eq (f a), Monoid (f a)) => (f a -> m (f a, Maybe (f a))) -> (f a -> f a -> m (f a)) -> t m (f a) -> t m (f a) -- | Run the action m b before the stream yields its first -- element. -- -- Same as the following but more efficient due to fusion: -- --
-- >>> before action xs = Stream.nilM action <> xs -- -- >>> before action xs = Stream.concatMap (const xs) (Stream.fromEffect action) --before :: (IsStream t, Monad m) => m b -> t m a -> t m a -- | Like after, with following differences: -- --
-- after_ action xs = xs <> 'nilM' action ---- -- Pre-release after_ :: (IsStream t, Monad m) => m b -> t m a -> t m a -- | Run the action m b whenever the stream t m a stops -- normally, or if it is garbage collected after a partial lazy -- evaluation. -- -- The semantics of the action m b are similar to the semantics -- of cleanup action in bracket. -- -- See also after_ after :: (IsStream t, MonadRunInIO m) => m b -> t m a -> t m a -- | Like bracket but with following differences: -- --
-- evalStateT s = Stream.map snd . Stream.runStateT s ---- -- Internal evalStateT :: Monad m => m s -> SerialT (StateT s m) a -> SerialT m a -- | Run a stateful (StateT) stream transformation using a given state. -- -- This is supported only for SerialT as concurrent state updation -- may not be safe. -- --
-- usingStateT s f = evalStateT s . f . liftInner ---- -- See also: scanl' -- -- Internal usingStateT :: Monad m => m s -> (SerialT (StateT s m) a -> SerialT (StateT s m) a) -> SerialT m a -> SerialT m a -- | Evaluate the inner monad of a stream as StateT and emit the -- resulting state and value pair after each step. -- -- This is supported only for SerialT as concurrent state updation -- may not be safe. runStateT :: Monad m => m s -> SerialT (StateT s m) a -> SerialT m (s, a) -- | sampleFromthen offset stride samples the element at -- offset index and then every element at strides of -- stride. -- --
-- >>> Stream.toList $ Stream.sampleFromThen 2 3 $ Stream.enumerateFromTo 0 10 -- [2,5,8] ---- -- Pre-release sampleFromThen :: (IsStream t, Monad m, Functor (t m)) => Int -> Int -> t m a -> t m a -- | Like sampleInterval but samples at the beginning of the time -- window. -- --
-- sampleIntervalStart n = Stream.catMaybes . Stream.intervalsOf n Fold.one ---- -- Pre-release sampleIntervalStart :: (IsStream t, MonadAsync m, Functor (t m)) => Double -> t m a -> t m a -- | Continuously evaluate the input stream and sample the last event in -- time window of n seconds. -- -- This is also known as throttle in some libraries. -- --
-- sampleIntervalEnd n = Stream.catMaybes . Stream.intervalsOf n Fold.last ---- -- Pre-release sampleIntervalEnd :: (IsStream t, MonadAsync m, Functor (t m)) => Double -> t m a -> t m a -- | Like sampleBurstEnd but samples the event at the beginning of -- the burst instead of at the end of it. -- -- Pre-release sampleBurstStart :: (IsStream t, MonadAsync m, Functor (t m)) => Double -> t m a -> t m a -- | Sample one event at the end of each burst of events. A burst is a -- group of events close together in time, it ends when an event is -- spaced by more than the specified time interval (in seconds) from the -- previous event. -- -- This is known as debounce in some libraries. -- -- The clock granularity is 10 ms. -- -- Pre-release sampleBurstEnd :: (IsStream t, MonadAsync m, Functor (t m)) => Double -> t m a -> t m a -- | Sort the input stream using a supplied comparison function. -- -- O(n) space -- -- Note: this is not the fastest possible implementation as of now. -- -- Pre-release sortBy :: MonadCatch m => (a -> a -> Ordering) -> SerialT m a -> SerialT m a -- | intersectBy is essentially a filtering operation that retains -- only those elements in the first stream that are present in the second -- stream. -- --
-- >>> Stream.toList $ Stream.intersectBy (==) (Stream.fromList [1,2,2,4]) (Stream.fromList [2,1,1,3]) -- [1,2,2] ---- --
-- >>> Stream.toList $ Stream.intersectBy (==) (Stream.fromList [2,1,1,3]) (Stream.fromList [1,2,2,4]) -- [2,1,1] ---- -- intersectBy is similar to but not the same as joinInner: -- --
-- >>> Stream.toList $ fmap fst $ Stream.joinInner (==) (Stream.fromList [1,2,2,4]) (Stream.fromList [2,1,1,3]) -- [1,1,2,2] ---- -- Space: O(n) where n is the number of elements in the second -- stream. -- -- Time: O(m x n) where m is the number of elements in the first -- stream and n is the number of elements in the second stream. -- -- Pre-release intersectBy :: (IsStream t, Monad m) => (a -> a -> Bool) -> t m a -> t m a -> t m a -- | Like intersectBy but works only on streams sorted in ascending -- order. -- -- Space: O(1) -- -- Time: O(m+n) -- -- Pre-release intersectBySorted :: (IsStream t, Monad m) => (a -> a -> Ordering) -> t m a -> t m a -> t m a -- | Delete first occurrences of those elements from the first stream that -- are present in the second stream. If an element occurs multiple times -- in the second stream as many occurrences of it are deleted from the -- first stream. -- --
-- >>> Stream.toList $ Stream.differenceBy (==) (Stream.fromList [1,2,2]) (Stream.fromList [1,2,3]) -- [2] ---- -- The following laws hold: -- --
-- (s1 serial s2) `differenceBy eq` s1 === s2 -- (s1 wSerial s2) `differenceBy eq` s1 === s2 ---- -- Same as the list // operation. -- -- Space: O(m) where m is the number of elements in the first -- stream. -- -- Time: O(m x n) where m is the number of elements in the first -- stream and n is the number of elements in the second stream. -- -- Pre-release differenceBy :: (IsStream t, Monad m) => (a -> a -> Bool) -> t m a -> t m a -> t m a -- | Like differenceBy but works only on sorted streams. -- -- Space: O(1) -- -- Unimplemented mergeDifferenceBy :: (a -> a -> Ordering) -> t m a -> t m a -> t m a -- | This is essentially an append operation that appends all the extra -- occurrences of elements from the second stream that are not already -- present in the first stream. -- --
-- >>> Stream.toList $ Stream.unionBy (==) (Stream.fromList [1,2,2,4]) (Stream.fromList [1,1,2,3]) -- [1,2,2,4,3] ---- -- Equivalent to the following except that s1 is evaluated only -- once: -- --
-- unionBy eq s1 s2 = s1 `serial` (s2 `differenceBy eq` s1) ---- -- Similar to joinOuter but not the same. -- -- Space: O(n) -- -- Time: O(m x n) -- -- Pre-release unionBy :: (IsStream t, MonadAsync m, Semigroup (t m a)) => (a -> a -> Bool) -> t m a -> t m a -> t m a -- | Like unionBy but works only on sorted streams. -- -- Space: O(1) -- -- Unimplemented mergeUnionBy :: (a -> a -> Ordering) -> t m a -> t m a -> t m a -- | This is the same as outerProduct but less efficient. -- -- The second stream is evaluated multiple times. If the second stream is -- consume-once stream then it can be cached in an Array before -- calling this function. Caching may also improve performance if the -- stream is expensive to evaluate. -- -- Time: O(m x n) -- -- Pre-release crossJoin :: Monad (t m) => t m a -> t m b -> t m (a, b) -- | For all elements in t m a, for all elements in t m b -- if a and b are equal by the given equality pedicate -- then return the tuple (a, b). -- -- The second stream is evaluated multiple times. If the stream is a -- consume-once stream then the caller should cache it (e.g. in a -- Array) before calling this function. Caching may also improve -- performance if the stream is expensive to evaluate. -- -- For space efficiency use the smaller stream as the second stream. -- -- You should almost always use joinInnerMap instead of joinInner. -- joinInnerMap is an order of magnitude faster. joinInner may be used -- when the second stream is generated from a seed, therefore, need not -- be stored in memory and the amount of memory it takes is a concern. -- -- Space: O(n) assuming the second stream is cached in memory. -- -- Time: O(m x n) -- -- Pre-release joinInner :: forall (t :: (Type -> Type) -> Type -> Type) m a b. (IsStream t, Monad m) => (a -> b -> Bool) -> t m a -> t m b -> t m (a, b) -- | Like joinInner but uses a Map for efficiency. -- -- If the input streams have duplicate keys, the behavior is undefined. -- -- For space efficiency use the smaller stream as the second stream. -- -- Space: O(n) -- -- Time: O(m + n) -- -- Pre-release joinInnerMap :: (IsStream t, Monad m, Ord k) => t m (k, a) -> t m (k, b) -> t m (k, a, b) -- | Like joinInner but works only on sorted streams. -- -- Space: O(1) -- -- Time: O(m + n) -- -- Unimplemented joinInnerMerge :: (a -> b -> Ordering) -> t m a -> t m b -> t m (a, b) -- | Like joinLeft but works only on sorted streams. -- -- Space: O(1) -- -- Time: O(m + n) -- -- Unimplemented mergeLeftJoin :: (a -> b -> Ordering) -> t m a -> t m b -> t m (a, Maybe b) -- | Like joinLeft but uses a hashmap for efficiency. -- -- Space: O(n) -- -- Time: O(m + n) -- -- Pre-release joinLeftMap :: (IsStream t, Ord k, Monad m) => t m (k, a) -> t m (k, b) -> t m (k, a, Maybe b) -- | Like joinOuter but works only on sorted streams. -- -- Space: O(1) -- -- Time: O(m + n) -- -- Unimplemented mergeOuterJoin :: (a -> b -> Ordering) -> t m a -> t m b -> t m (Maybe a, Maybe b) -- | Like joinOuter but uses a Map for efficiency. -- -- Space: O(m + n) -- -- Time: O(m + n) -- -- Pre-release joinOuterMap :: (IsStream t, Ord k, MonadIO m) => t m (k, a) -> t m (k, b) -> t m (k, Maybe a, Maybe b) -- | Specify the maximum number of threads that can be spawned concurrently -- for any concurrent combinator in a stream. A value of 0 resets the -- thread limit to default, a negative value means there is no limit. The -- default value is 1500. maxThreads does not affect -- ParallelT streams as they can use unbounded number of -- threads. -- -- When the actions in a stream are IO bound, having blocking IO calls, -- this option can be used to control the maximum number of in-flight IO -- requests. When the actions are CPU bound this option can be used to -- control the amount of CPU used by the stream. -- -- Since: 0.4.0 (Streamly) maxThreads :: IsStream t => Int -> t m a -> t m a -- | Specify the maximum size of the buffer for storing the results from -- concurrent computations. If the buffer becomes full we stop spawning -- more concurrent tasks until there is space in the buffer. A value of 0 -- resets the buffer size to default, a negative value means there is no -- limit. The default value is 1500. -- -- CAUTION! using an unbounded maxBuffer value (i.e. a negative -- value) coupled with an unbounded maxThreads value is a recipe -- for disaster in presence of infinite streams, or very large streams. -- Especially, it must not be used when pure is used in -- ZipAsyncM streams as pure in applicative zip streams -- generates an infinite stream causing unbounded concurrent generation -- with no limit on the buffer or threads. -- -- Since: 0.4.0 (Streamly) maxBuffer :: IsStream t => Int -> t m a -> t m a maxYields :: IsStream t => Maybe Int64 -> t m a -> t m a -- | Specify the pull rate of a stream. A Nothing value resets the -- rate to default which is unlimited. When the rate is specified, -- concurrent production may be ramped up or down automatically to -- achieve the specified yield rate. The specific behavior for different -- styles of Rate specifications is documented under Rate. -- The effective maximum production rate achieved by a stream is governed -- by: -- --
-- fromPure a = a `cons` nil ---- -- Create a singleton stream from a pure value. -- -- The following holds in monadic streams, but not in Zip streams: -- --
-- fromPure = pure -- fromPure = fromEffect . pure ---- -- In Zip applicative streams fromPure is not the same as -- pure because in that case pure is equivalent to -- repeat instead. fromPure and pure are equally -- efficient, in other cases fromPure may be slightly more -- efficient than the other equivalent definitions. -- -- Since: 0.8.0 (Renamed yield to fromPure) fromPure :: IsStream t => a -> t m a -- |
-- fromEffect m = m `consM` nil ---- -- Create a singleton stream from a monadic action. -- --
-- > Stream.toList $ Stream.fromEffect getLine -- hello -- ["hello"] ---- -- Since: 0.8.0 (Renamed yieldM to fromEffect) fromEffect :: (Monad m, IsStream t) => m a -> t m a -- |
-- >>> repeatM = fix . consM -- -- >>> repeatM = cycle1 . fromEffect ---- -- Generate a stream by repeatedly executing a monadic action forever. -- --
-- >>> :{ -- repeatAsync = -- Stream.repeatM (threadDelay 1000000 >> print 1) -- & Stream.take 10 -- & Stream.fromAsync -- & Stream.drain -- :} ---- -- Concurrent, infinite (do not use with fromParallel) repeatM :: (IsStream t, MonadAsync m) => m a -> t m a -- | timesWith g returns a stream of time value tuples. The first -- component of the tuple is an absolute time reference (epoch) denoting -- the start of the stream and the second component is a time relative to -- the reference. -- -- The argument g specifies the granularity of the relative time -- in seconds. A lower granularity clock gives higher precision but is -- more expensive in terms of CPU usage. Any granularity lower than 1 ms -- is treated as 1 ms. -- --
-- >>> import Control.Concurrent (threadDelay) -- -- >>> import Streamly.Internal.Data.Stream.IsStream.Common as Stream (timesWith) -- -- >>> Stream.mapM_ (\x -> print x >> threadDelay 1000000) $ Stream.take 3 $ Stream.timesWith 0.01 -- (AbsTime (TimeSpec {sec = ..., nsec = ...}),RelTime64 (NanoSecond64 ...)) -- (AbsTime (TimeSpec {sec = ..., nsec = ...}),RelTime64 (NanoSecond64 ...)) -- (AbsTime (TimeSpec {sec = ..., nsec = ...}),RelTime64 (NanoSecond64 ...)) ---- -- Note: This API is not safe on 32-bit machines. -- -- Pre-release timesWith :: (IsStream t, MonadAsync m) => Double -> t m (AbsTime, RelTime64) -- | absTimesWith g returns a stream of absolute timestamps using -- a clock of granularity g specified in seconds. A low -- granularity clock is more expensive in terms of CPU usage. Any -- granularity lower than 1 ms is treated as 1 ms. -- --
-- >>> Stream.mapM_ print $ Stream.delayPre 1 $ Stream.take 3 $ absTimesWith 0.01 -- AbsTime (TimeSpec {sec = ..., nsec = ...}) -- AbsTime (TimeSpec {sec = ..., nsec = ...}) -- AbsTime (TimeSpec {sec = ..., nsec = ...}) ---- -- Note: This API is not safe on 32-bit machines. -- -- Pre-release absTimesWith :: (IsStream t, MonadAsync m, Functor (t m)) => Double -> t m AbsTime -- | relTimesWith g returns a stream of relative time values -- starting from 0, using a clock of granularity g specified in -- seconds. A low granularity clock is more expensive in terms of CPU -- usage. Any granularity lower than 1 ms is treated as 1 ms. -- --
-- >>> Stream.mapM_ print $ Stream.delayPre 1 $ Stream.take 3 $ Stream.relTimesWith 0.01 -- RelTime64 (NanoSecond64 ...) -- RelTime64 (NanoSecond64 ...) -- RelTime64 (NanoSecond64 ...) ---- -- Note: This API is not safe on 32-bit machines. -- -- Pre-release relTimesWith :: (IsStream t, MonadAsync m, Functor (t m)) => Double -> t m RelTime64 -- | We can create higher order folds using foldContinue. We can -- fold a number of streams to a given fold efficiently with full stream -- fusion. For example, to fold a list of streams on the same sum fold: -- --
-- concatFold = Prelude.foldl Stream.foldContinue Fold.sum ---- --
-- fold f = Fold.extractM . Stream.foldContinue f ---- -- Internal foldContinue :: Monad m => Fold m a b -> SerialT m a -> Fold m a b -- | Fold a stream using the supplied left Fold and reducing the -- resulting expression strictly at each step. The behavior is similar to -- foldl'. A Fold can terminate early without consuming -- the full stream. See the documentation of individual Folds for -- termination behavior. -- --
-- >>> Stream.fold Fold.sum (Stream.enumerateFromTo 1 100) -- 5050 ---- -- Folds never fail, therefore, they produce a default value even when no -- input is provided. It means we can always fold an empty stream and get -- a valid result. For example: -- --
-- >>> Stream.fold Fold.sum Stream.nil -- 0 ---- -- However, foldMany on an empty stream results in an empty -- stream. Therefore, Stream.fold f is not the same as -- Stream.head . Stream.foldMany f. -- --
-- fold f = Stream.parse (Parser.fromFold f) --fold :: Monad m => Fold m a b -> SerialT m a -> m b -- |
-- map = fmap ---- -- Same as fmap. -- --
-- > D.toList $ D.map (+1) $ D.fromList [1,2,3] -- [2,3,4] --map :: (IsStream t, Monad m) => (a -> b) -> t m a -> t m b -- | scanlMAfter' accumulate initial done stream is like -- scanlM' except that it provides an additional done -- function to be applied on the accumulator when the stream stops. The -- result of done is also emitted in the stream. -- -- This function can be used to allocate a resource in the beginning of -- the scan and release it when the stream ends or to flush the internal -- state of the scan at the end. -- -- Pre-release scanlMAfter' :: (IsStream t, Monad m) => (b -> a -> m b) -> m b -> (b -> m b) -> t m a -> t m b postscanlMAfter' :: (IsStream t, Monad m) => (b -> a -> m b) -> m b -> (b -> m b) -> t m a -> t m b -- | Like postscanl' but with a monadic step function and a -- monadic seed. -- --
-- >>> postscanlM' f z xs = Stream.drop 1 $ Stream.scanlM' f z xs ---- -- Since: 0.7.0 -- -- Since: 0.8.0 (signature change) postscanlM' :: (IsStream t, Monad m) => (b -> a -> m b) -> m b -> t m a -> t m b -- | A stateful mapM, equivalent to a left scan, more like -- mapAccumL. Hopefully, this is a better alternative to scan. -- Separation of state from the output makes it easier to think in terms -- of a shared state, and also makes it easier to keep the state fully -- strict and the output lazy. -- -- See also: scanlM' -- -- Pre-release smapM :: (IsStream t, Monad m) => (s -> a -> m (s, b)) -> m s -> t m a -> t m b -- | Like foldMany but appends empty fold output if the fold and -- stream termination aligns: -- --
-- >>> f = Fold.take 2 Fold.sum -- -- >>> Stream.toList $ Stream.foldManyPost f $ Stream.fromList [] -- [0] -- -- >>> Stream.toList $ Stream.foldManyPost f $ Stream.fromList [1..9] -- [3,7,11,15,9] -- -- >>> Stream.toList $ Stream.foldManyPost f $ Stream.fromList [1..10] -- [3,7,11,15,19,0] ---- -- Pre-release foldManyPost :: (IsStream t, Monad m) => Fold m a b -> t m a -> t m b -- | Take first n elements from the stream and discard the rest. take :: (IsStream t, Monad m) => Int -> t m a -> t m a -- | End the stream as soon as the predicate fails on an element. takeWhile :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> t m a takeEndBy :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> t m a -- | Discard first n elements from the stream and take the rest. drop :: (IsStream t, Monad m) => Int -> t m a -> t m a -- | Find all the indices where the element in the stream satisfies the -- given predicate. -- --
-- findIndices = fold Fold.findIndices --findIndices :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> t m Int -- | Insert an effect and its output before consuming an element of a -- stream except the first one. -- --
-- >>> Stream.toList $ Stream.trace putChar $ Stream.intersperseM (putChar '.' >> return ',') $ Stream.fromList "hello" -- h.,e.,l.,l.,o"h,e,l,l,o" ---- -- Be careful about the order of effects. In the above example we used -- trace after the intersperse, if we use it before the intersperse the -- output would be he.l.l.o."h,e,l,l,o". -- --
-- >>> Stream.toList $ Stream.intersperseM (putChar '.' >> return ',') $ Stream.trace putChar $ Stream.fromList "hello" -- he.l.l.o."h,e,l,l,o" --intersperseM :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a -- | Intersperse a monadic action into the input stream after every -- n seconds. -- --
-- > import Control.Concurrent (threadDelay) -- > Stream.drain $ Stream.interjectSuffix 1 (putChar ',') $ Stream.mapM (x -> threadDelay 1000000 >> putChar x) $ Stream.fromList "hello" -- h,e,l,l,o ---- -- Pre-release interjectSuffix :: (IsStream t, MonadAsync m) => Double -> m a -> t m a -> t m a -- | Returns the elements of the stream in reverse order. The stream must -- be finite. Note that this necessarily buffers the entire stream in -- memory. -- --
-- >>> reverse = Stream.foldlT (flip Stream.cons) Stream.nil ---- -- Since 0.7.0 (Monad m constraint) -- -- Since: 0.1.1 reverse :: (IsStream t, Monad m) => t m a -> t m a -- | Like reverse but several times faster, requires a -- Storable instance. -- -- Pre-release reverse' :: (IsStream t, MonadIO m, Unbox a) => t m a -> t m a -- | Make the stream producer and consumer run concurrently by introducing -- a buffer between them. The producer thread evaluates the input stream -- until the buffer fills, it terminates if the buffer is full and a -- worker thread is kicked off again to evaluate the remaining stream -- when there is space in the buffer. The consumer consumes the stream -- lazily from the buffer. -- -- Since: 0.2.0 (Streamly) mkAsync :: (IsStream t, MonadAsync m) => t m a -> t m a -- | Make the stream producer and consumer run concurrently by introducing -- a buffer between them. The producer thread evaluates the input stream -- until the buffer fills, it blocks if the buffer is full until there is -- space in the buffer. The consumer consumes the stream lazily from the -- buffer. -- --
-- mkParallel = IsStream.fromStreamD . mkParallelD . IsStream.toStreamD ---- -- Pre-release mkParallel :: (IsStream t, MonadAsync m) => t m a -> t m a -- | Like parallel but stops the output as soon as the first -- stream stops. -- -- Pre-release parallelFst :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a -- | Given a stream value in the underlying monad, lift and join the -- underlying monad with the stream monad. -- --
-- >>> concatM = Stream.concat . Stream.fromEffect -- -- >>> concatM = Stream.concat . lift -- requires (MonadTrans t) -- -- >>> concatM = join . lift -- requires (MonadTrans t, Monad (t m)) ---- -- See also: concat, sequence -- -- Internal concatM :: (IsStream t, Monad m) => m (t m a) -> t m a -- | Map a stream producing monadic function on each element of the stream -- and then flatten the results into a single stream. Since the stream -- generation function is monadic, unlike concatMap, it can -- produce an effect at the beginning of each iteration of the inner -- loop. concatMapM :: (IsStream t, Monad m) => (a -> m (t m b)) -> t m a -> t m b -- | Map a stream producing function on each element of the stream and then -- flatten the results into a single stream. -- --
-- >>> concatMap f = Stream.concatMapM (return . f) -- -- >>> concatMap f = Stream.concatMapWith Stream.serial f -- -- >>> concatMap f = Stream.concat . Stream.map f --concatMap :: (IsStream t, Monad m) => (a -> t m b) -> t m a -> t m b -- | Like splitOn but the separator is a sequence of elements -- instead of a single element. -- -- For illustration, let's define a function that operates on pure lists: -- --
-- >>> splitOnSeq' pat xs = Stream.toList $ Stream.splitOnSeq (Array.fromList pat) Fold.toList (Stream.fromList xs) ---- --
-- >>> splitOnSeq' "" "hello" -- ["h","e","l","l","o"] ---- --
-- >>> splitOnSeq' "hello" "" -- [""] ---- --
-- >>> splitOnSeq' "hello" "hello" -- ["",""] ---- --
-- >>> splitOnSeq' "x" "hello" -- ["hello"] ---- --
-- >>> splitOnSeq' "h" "hello" -- ["","ello"] ---- --
-- >>> splitOnSeq' "o" "hello" -- ["hell",""] ---- --
-- >>> splitOnSeq' "e" "hello" -- ["h","llo"] ---- --
-- >>> splitOnSeq' "l" "hello" -- ["he","","o"] ---- --
-- >>> splitOnSeq' "ll" "hello" -- ["he","o"] ---- -- splitOnSeq is an inverse of intercalate. The following -- law always holds: -- --
-- intercalate . splitOnSeq == id ---- -- The following law holds when the separator is non-empty and contains -- none of the elements present in the input lists: -- --
-- splitOnSeq . intercalate == id ---- --
-- >>> splitOnSeq pat f = Stream.foldManyPost (Fold.takeEndBySeq_ pat f) ---- -- Pre-release splitOnSeq :: (IsStream t, MonadIO m, Storable a, Unbox a, Enum a, Eq a) => Array a -> Fold m a b -> t m a -> t m b -- | Like zipWith but using a monadic zipping function. zipWithM :: (IsStream t, Monad m) => (a -> b -> m c) -> t m a -> t m b -> t m c -- | Stream a is evaluated first, followed by stream b, -- the resulting elements a and b are then zipped using -- the supplied zip function and the result c is yielded to the -- consumer. -- -- If stream a or stream b ends, the zipped stream -- ends. If stream b ends first, the element a from -- previous evaluation of stream a is discarded. -- --
-- > D.toList $ D.zipWith (+) (D.fromList [1,2,3]) (D.fromList [4,5,6]) -- [5,7,9] --zipWith :: (IsStream t, Monad m) => (a -> b -> c) -> t m a -> t m b -> t m c -- | Same as fromPure yield :: IsStream t => a -> t m a -- | Same as fromEffect yieldM :: (Monad m, IsStream t) => m a -> t m a -- | Types that can be enumerated as a stream. The operations in this type -- class are equivalent to those in the Enum type class, except -- that these generate a stream instead of a list. Use the functions in -- Streamly.Internal.Data.Stream.Enumeration module to define new -- instances. class Enum a => Enumerable a -- | enumerateFrom from generates a stream starting with the -- element from, enumerating up to maxBound when the type -- is Bounded or generating an infinite stream when the type is -- not Bounded. -- --
-- >>> Stream.toList $ Stream.take 4 $ Stream.enumerateFrom (0 :: Int) -- [0,1,2,3] ---- -- For Fractional types, enumeration is numerically stable. -- However, no overflow or underflow checks are performed. -- --
-- >>> Stream.toList $ Stream.take 4 $ Stream.enumerateFrom 1.1 -- [1.1,2.1,3.1,4.1] --enumerateFrom :: (Enumerable a, IsStream t, Monad m) => a -> t m a -- | Generate a finite stream starting with the element from, -- enumerating the type up to the value to. If to is -- smaller than from then an empty stream is returned. -- --
-- >>> Stream.toList $ Stream.enumerateFromTo 0 4 -- [0,1,2,3,4] ---- -- For Fractional types, the last element is equal to the -- specified to value after rounding to the nearest integral -- value. -- --
-- >>> Stream.toList $ Stream.enumerateFromTo 1.1 4 -- [1.1,2.1,3.1,4.1] -- -- >>> Stream.toList $ Stream.enumerateFromTo 1.1 4.6 -- [1.1,2.1,3.1,4.1,5.1] --enumerateFromTo :: (Enumerable a, IsStream t, Monad m) => a -> a -> t m a -- | enumerateFromThen from then generates a stream whose first -- element is from, the second element is then and the -- successive elements are in increments of then - from. -- Enumeration can occur downwards or upwards depending on whether -- then comes before or after from. For Bounded -- types the stream ends when maxBound is reached, for unbounded -- types it keeps enumerating infinitely. -- --
-- >>> Stream.toList $ Stream.take 4 $ Stream.enumerateFromThen 0 2 -- [0,2,4,6] -- -- >>> Stream.toList $ Stream.take 4 $ Stream.enumerateFromThen 0 (-2) -- [0,-2,-4,-6] --enumerateFromThen :: (Enumerable a, IsStream t, Monad m) => a -> a -> t m a -- | enumerateFromThenTo from then to generates a finite stream -- whose first element is from, the second element is -- then and the successive elements are in increments of -- then - from up to to. Enumeration can occur -- downwards or upwards depending on whether then comes before -- or after from. -- --
-- >>> Stream.toList $ Stream.enumerateFromThenTo 0 2 6 -- [0,2,4,6] -- -- >>> Stream.toList $ Stream.enumerateFromThenTo 0 (-2) (-6) -- [0,-2,-4,-6] --enumerateFromThenTo :: (Enumerable a, IsStream t, Monad m) => a -> a -> a -> t m a -- |
-- enumerate = enumerateFrom minBound ---- -- Enumerate a Bounded type from its minBound to -- maxBound enumerate :: (IsStream t, Monad m, Bounded a, Enumerable a) => t m a -- |
-- enumerateTo = enumerateFromTo minBound ---- -- Enumerate a Bounded type from its minBound to specified -- value. enumerateTo :: (IsStream t, Monad m, Bounded a, Enumerable a) => a -> t m a -- |
-- enumerateFromBounded = enumerateFromTo from maxBound ---- -- enumerateFrom for Bounded Enum types. enumerateFromBounded :: (IsStream t, Monad m, Enumerable a, Bounded a) => a -> t m a -- | enumerateFromTo for Enum types not larger than -- Int. enumerateFromToSmall :: (IsStream t, Monad m, Enum a) => a -> a -> t m a -- | enumerateFromThenTo for Enum types not larger than -- Int. enumerateFromThenToSmall :: (IsStream t, Monad m, Enum a) => a -> a -> a -> t m a -- | enumerateFromThen for Enum types not larger than -- Int. -- -- Note: We convert the Enum to Int and enumerate the -- Int. If a type is bounded but does not have a Bounded -- instance then we can go on enumerating it beyond the legal values of -- the type, resulting in the failure of toEnum when converting -- back to Enum. Therefore we require a Bounded instance -- for this function to be safely used. enumerateFromThenSmallBounded :: (IsStream t, Monad m, Enumerable a, Bounded a) => a -> a -> t m a -- | Enumerate an Integral type. enumerateFromIntegral from -- generates a stream whose first element is from and the -- successive elements are in increments of 1. The stream is -- bounded by the size of the Integral type. -- --
-- >>> Stream.toList $ Stream.take 4 $ Stream.enumerateFromIntegral (0 :: Int) -- [0,1,2,3] --enumerateFromIntegral :: (IsStream t, Monad m, Integral a, Bounded a) => a -> t m a -- | Enumerate an Integral type in steps. -- enumerateFromThenIntegral from then generates a stream whose -- first element is from, the second element is then -- and the successive elements are in increments of then - from. -- The stream is bounded by the size of the Integral type. -- --
-- >>> Stream.toList $ Stream.take 4 $ Stream.enumerateFromThenIntegral (0 :: Int) 2 -- [0,2,4,6] -- -- >>> Stream.toList $ Stream.take 4 $ Stream.enumerateFromThenIntegral (0 :: Int) (-2) -- [0,-2,-4,-6] --enumerateFromThenIntegral :: (IsStream t, Monad m, Integral a, Bounded a) => a -> a -> t m a -- | Enumerate an Integral type up to a given limit. -- enumerateFromToIntegral from to generates a finite stream -- whose first element is from and successive elements are in -- increments of 1 up to to. -- --
-- >>> Stream.toList $ Stream.enumerateFromToIntegral 0 4 -- [0,1,2,3,4] --enumerateFromToIntegral :: (IsStream t, Monad m, Integral a) => a -> a -> t m a -- | Enumerate an Integral type in steps up to a given limit. -- enumerateFromThenToIntegral from then to generates a finite -- stream whose first element is from, the second element is -- then and the successive elements are in increments of -- then - from up to to. -- --
-- >>> Stream.toList $ Stream.enumerateFromThenToIntegral 0 2 6 -- [0,2,4,6] -- -- >>> Stream.toList $ Stream.enumerateFromThenToIntegral 0 (-2) (-6) -- [0,-2,-4,-6] --enumerateFromThenToIntegral :: (IsStream t, Monad m, Integral a) => a -> a -> a -> t m a -- | enumerateFromStepIntegral from step generates an infinite -- stream whose first element is from and the successive -- elements are in increments of step. -- -- CAUTION: This function is not safe for finite integral types. It does -- not check for overflow, underflow or bounds. -- --
-- >>> Stream.toList $ Stream.take 4 $ Stream.enumerateFromStepIntegral 0 2 -- [0,2,4,6] -- -- >>> Stream.toList $ Stream.take 3 $ Stream.enumerateFromStepIntegral 0 (-2) -- [0,-2,-4] --enumerateFromStepIntegral :: (IsStream t, Monad m, Integral a) => a -> a -> t m a -- | Numerically stable enumeration from a Fractional number in -- steps of size 1. enumerateFromFractional from -- generates a stream whose first element is from and the -- successive elements are in increments of 1. No overflow or -- underflow checks are performed. -- -- This is the equivalent to enumFrom for Fractional types. -- For example: -- --
-- >>> Stream.toList $ Stream.take 4 $ Stream.enumerateFromFractional 1.1 -- [1.1,2.1,3.1,4.1] --enumerateFromFractional :: (IsStream t, Monad m, Fractional a) => a -> t m a -- | Numerically stable enumeration from a Fractional number to a -- given limit. enumerateFromToFractional from to generates a -- finite stream whose first element is from and successive -- elements are in increments of 1 up to to. -- -- This is the equivalent of enumFromTo for Fractional -- types. For example: -- --
-- >>> Stream.toList $ Stream.enumerateFromToFractional 1.1 4 -- [1.1,2.1,3.1,4.1] -- -- >>> Stream.toList $ Stream.enumerateFromToFractional 1.1 4.6 -- [1.1,2.1,3.1,4.1,5.1] ---- -- Notice that the last element is equal to the specified to -- value after rounding to the nearest integer. enumerateFromToFractional :: (IsStream t, Monad m, Fractional a, Ord a) => a -> a -> t m a -- | Numerically stable enumeration from a Fractional number in -- steps. enumerateFromThenFractional from then generates a -- stream whose first element is from, the second element is -- then and the successive elements are in increments of -- then - from. No overflow or underflow checks are performed. -- -- This is the equivalent of enumFromThen for Fractional -- types. For example: -- --
-- >>> Stream.toList $ Stream.take 4 $ Stream.enumerateFromThenFractional 1.1 2.1 -- [1.1,2.1,3.1,4.1] -- -- >>> Stream.toList $ Stream.take 4 $ Stream.enumerateFromThenFractional 1.1 (-2.1) -- [1.1,-2.1,-5.300000000000001,-8.500000000000002] --enumerateFromThenFractional :: (IsStream t, Monad m, Fractional a) => a -> a -> t m a -- | Numerically stable enumeration from a Fractional number in -- steps up to a given limit. enumerateFromThenToFractional from then -- to generates a finite stream whose first element is -- from, the second element is then and the successive -- elements are in increments of then - from up to to. -- -- This is the equivalent of enumFromThenTo for Fractional -- types. For example: -- --
-- >>> Stream.toList $ Stream.enumerateFromThenToFractional 0.1 2 6 -- [0.1,2.0,3.9,5.799999999999999] -- -- >>> Stream.toList $ Stream.enumerateFromThenToFractional 0.1 (-2) (-6) -- [0.1,-2.0,-4.1000000000000005,-6.200000000000001] --enumerateFromThenToFractional :: (IsStream t, Monad m, Fractional a, Ord a) => a -> a -> a -> t m a fromStream :: (IsStream t, Monad m) => Stream m a -> t m a toStream :: (IsStream t, Monad m) => t m a -> Stream m a module Streamly.Internal.Data.Unfold.Prelude -- | Run the alloc action a -> m c with async exceptions -- disabled but keeping blocking operations interruptible (see -- mask). Use the output c as input to Unfold m c -- b to generate an output stream. When unfolding use the supplied -- try operation forall s. m s -> m (Either e s) to -- catch synchronous exceptions. If an exception occurs run the exception -- handling unfold Unfold m (c, e) b. -- -- The cleanup action c -> m d, runs whenever the stream ends -- normally, due to a sync or async exception or if it gets garbage -- collected after a partial lazy evaluation. See bracket for the -- semantics of the cleanup action. -- -- gbracket can express all other exception handling combinators. -- -- Inhibits stream fusion -- -- Pre-release gbracket :: MonadRunInIO m => (a -> m c) -> (c -> m d) -> Unfold m (c, e) b -> (forall s. m s -> m (Either e s)) -> Unfold m c b -> Unfold m a b -- | Unfold the input a using Unfold m a b, run an action -- on a whenever the unfold stops normally, or if it is garbage -- collected after a partial lazy evaluation. -- -- The semantics of the action a -> m c are similar to the -- cleanup action semantics in bracket. -- -- See also after_ -- -- Pre-release after :: MonadRunInIO m => (a -> m c) -> Unfold m a b -> Unfold m a b -- | Unfold the input a using Unfold m a b, run an action -- on a whenever the unfold stops normally, aborts due to an -- exception or if it is garbage collected after a partial lazy -- evaluation. -- -- The semantics of the action a -> m c are similar to the -- cleanup action semantics in bracket. -- --
-- finally release = bracket return release ---- -- See also finally_ -- -- Inhibits stream fusion -- -- Pre-release finally :: (MonadAsync m, MonadCatch m) => (a -> m c) -> Unfold m a b -> Unfold m a b -- | Run the alloc action a -> m c with async exceptions -- disabled but keeping blocking operations interruptible (see -- mask). Use the output c as input to Unfold m c -- b to generate an output stream. -- -- c is usually a resource under the state of monad m, -- e.g. a file handle, that requires a cleanup after use. The cleanup -- action c -> m d, runs whenever the stream ends normally, -- due to a sync or async exception or if it gets garbage collected after -- a partial lazy evaluation. -- -- bracket only guarantees that the cleanup action runs, and it -- runs with async exceptions enabled. The action must ensure that it can -- successfully cleanup the resource in the face of sync or async -- exceptions. -- -- When the stream ends normally or on a sync exception, cleanup action -- runs immediately in the current thread context, whereas in other cases -- it runs in the GC context, therefore, cleanup may be delayed until the -- GC gets to run. -- -- See also: bracket_, gbracket -- -- Inhibits stream fusion -- -- Pre-release bracket :: (MonadAsync m, MonadCatch m) => (a -> m c) -> (c -> m d) -> Unfold m c b -> Unfold m a b -- | Internal fromSVar :: MonadAsync m => Unfold m (SVar t m a) a -- | Internal fromProducer :: MonadAsync m => Unfold m (SVar t m a) a -- |
-- Stream.mapM_ (putStrLn . showEvent) $ watchPaths [Array.fromList "dir"] ---- -- Event is an opaque type. Accessor functions (e.g. -- showEvent above) provided in this module are used to determine -- the attributes of the event. -- -- Identical successive events may be coalesced into a single event. -- --
-- >>> watch = watchWith id ---- -- Pre-release watch :: NonEmpty (Array Word8) -> Stream IO Event -- | Same as watchWith using defaultConfig and recursive -- mode. -- --
-- >>> watchRecursive = watchWith (setRecursiveMode True) ---- -- See watchWith for pitfalls and bugs when using recursive watch -- on Linux. -- -- Pre-release watchRecursive :: NonEmpty (Array Word8) -> Stream IO Event -- | Start monitoring a list of file system paths for file system events -- with the supplied configuration operation over the -- defaultConfig. The paths could be files or directories. When -- recursive mode is set and the path is a directory, the whole directory -- tree under it is watched recursively. Monitoring starts from the -- current time onwards. The paths are specified as UTF-8 encoded -- Array of Word8. -- -- Non-existing Paths: the API fails if a watch is started on a -- non-exsting path. -- -- Performance: Note that recursive watch on a large directory -- tree could be expensive. When starting a watch, the whole tree must be -- read and watches are started on each directory in the tree. The -- initial time to start the watch as well as the memory required is -- proportional to the number of directories in the tree. -- -- Bugs: When new directories are created under the tree they are -- added to the watch on receiving the directory create event. However, -- the creation of a dir and adding a watch for it is not atomic. The -- implementation takes care of this and makes sure that watches are -- added for all directories. However, In the mean time, the directory -- may have received more events which may get lost. Handling of any such -- lost events is yet to be implemented. -- -- See the Linux inotify man page for more details. -- --
-- watchwith -- (setFollowSymLinks True . setUnwatchMoved False) -- [Array.fromList "dir"] ---- -- Pre-release watchWith :: (Config -> Config) -> NonEmpty (Array Word8) -> Stream IO Event -- | addToWatch cfg watch root subpath adds subpath to -- the list of paths being monitored under root via the watch -- handle watch. root must be an absolute path and -- subpath must be relative to root. -- -- Pre-release addToWatch :: Config -> Watch -> Array Word8 -> Array Word8 -> IO () -- | Remove an absolute root path from a Watch, if a path was moved -- after adding you need to provide the original path which was used to -- add the Watch. -- -- Pre-release removeFromWatch :: Watch -> Array Word8 -> IO () -- | An Event generated by the file system. Use the accessor functions to -- examine the event. -- -- Pre-release data Event Event :: CInt -> Word32 -> Word32 -> Array Word8 -> IntMap (Array Word8, Array Word8) -> Event [eventWd] :: Event -> CInt [eventFlags] :: Event -> Word32 [eventCookie] :: Event -> Word32 [eventRelPath] :: Event -> Array Word8 [eventMap] :: Event -> IntMap (Array Word8, Array Word8) -- | Get the watch root corresponding to the Event. -- -- Note that if a path was moved after adding to the watch, this will -- give the original path and not the new path after moving. -- -- TBD: we can possibly update the watch root on a move self event. -- -- Pre-release getRoot :: Event -> Array Word8 -- | Get the file system object path for which the event is generated, -- relative to the watched root. The path is a "/" separated array of -- bytes. -- -- Pre-release getRelPath :: Event -> Array Word8 -- | Get the absolute file system object path for which the event is -- generated. -- -- When the watch root is a symlink, the absolute path returned is via -- the original symlink and not through the resolved path. -- -- Pre-release getAbsPath :: Event -> Array Word8 -- | Cookie is set when a rename occurs. The cookie value can be used to -- connect the isMovedFrom and isMovedTo events, if both -- the events belong to the same move operation then they will have the -- same cookie value. -- -- Pre-release getCookie :: Event -> Cookie -- | Determine whether the event indicates a change of path of the -- monitored object itself. Note that the object may become unreachable -- or deleted after a change of path. -- -- Occurs only for a watched path -- -- Pre-release isRootPathEvent :: Event -> Bool -- | A path was removed from the watch explicitly using -- removeFromWatch or automatically (file was deleted, or -- filesystem was unmounted). -- -- Note that in recursive watch mode all the subdirectories are watch -- roots, therefore, they will all generate this event. -- -- Occurs only for a watched path -- -- Pre-release isRootUnwatched :: Event -> Bool -- | Watched file/directory was itself deleted. (This event also occurs if -- an object is moved to another filesystem, since mv(1) in effect copies -- the file to the other filesystem and then deletes it from the original -- filesystem.) In addition, an isRootUnwatched event will -- subsequently be generated for the watch descriptor. -- -- Note that in recursive watch mode all the subdirectories are watch -- roots, therefore, they will all generate this event. -- -- Occurs only for a watched path -- -- Pre-release isRootDeleted :: Event -> Bool -- | Watched file/directory was itself moved within the file system. -- -- Note that in recursive watch mode all the subdirectories are watch -- roots, therefore, they will all generate this event. -- -- Occurs only for a watched path -- -- Pre-release isRootMoved :: Event -> Bool -- | Filesystem containing watched object was unmounted. In addition, an -- isRootUnwatched event will subsequently be generated for the -- watch descriptor. -- -- Occurs only for a watched path -- -- Pre-release isRootUnmounted :: Event -> Bool -- | Determine whether the event indicates inode metadata change for an -- object contained within the monitored path. -- -- Metadata change may include, permissions (e.g., chmod(2)), timestamps -- (e.g., utimensat(2)), extended attributes (setxattr(2)), link count -- (since Linux 2.6.25; e.g., for the target of link(2) and for -- unlink(2)), and user/group ID (e.g., chown(2)). -- -- Can occur for watched path or a file inside it -- -- Pre-release isAttrsModified :: Event -> Bool -- | File was accessed (e.g. read, execve). -- -- Occurs only for a file inside the watched directory -- -- Pre-release isAccessed :: Event -> Bool -- | File or directory was opened. -- -- Occurs only for a file inside the watched directory -- -- Pre-release isOpened :: Event -> Bool -- | File opened for writing was closed. -- -- Occurs only for a file inside the watched directory -- -- Pre-release isWriteClosed :: Event -> Bool -- | File or directory opened for read but not write was closed. -- -- Can occur for watched path or a file inside it -- -- Pre-release isNonWriteClosed :: Event -> Bool -- | File/directory created in watched directory (e.g., open(2) O_CREAT, -- mkdir(2), link(2), symlink(2), bind(2) on a UNIX domain socket). -- -- Occurs only for an object inside the watched directory -- -- Pre-release isCreated :: Event -> Bool -- | File/directory deleted from watched directory. -- -- Occurs only for an object inside the watched directory -- -- Pre-release isDeleted :: Event -> Bool -- | Generated for the original path when an object is moved from under a -- monitored directory. -- -- Occurs only for an object inside the watched directory -- -- Pre-release isMovedFrom :: Event -> Bool -- | Generated for the new path when an object is moved under a monitored -- directory. -- -- Occurs only for an object inside the watched directory -- -- Pre-release isMovedTo :: Event -> Bool -- | Generated for a path that is moved from or moved to the monitored -- directory. -- --
-- >>> isMoved ev = isMovedFrom ev || isMovedTo ev ---- -- Occurs only for an object inside the watched directory -- -- Pre-release isMoved :: Event -> Bool -- | Determine whether the event indicates modification of an object within -- the monitored path. This event is generated only for files and not -- directories. -- -- Occurs only for an object inside the watched directory -- -- Pre-release isModified :: Event -> Bool -- | Determine whether the event is for a directory path. -- -- Pre-release isDir :: Event -> Bool -- | Event queue overflowed (WD is invalid for this event) and we may have -- lost some events.. The user application must scan everything under the -- watched paths to know the current state. -- -- Pre-release isEventsLost :: Event -> Bool -- | Convert an Event record to a String representation. showEvent :: Event -> String instance GHC.Show.Show Streamly.Internal.FileSystem.Event.Linux.WD instance GHC.Classes.Eq Streamly.Internal.FileSystem.Event.Linux.Cookie instance GHC.Show.Show Streamly.Internal.FileSystem.Event.Linux.Cookie instance GHC.Classes.Eq Streamly.Internal.FileSystem.Event.Linux.Event instance GHC.Classes.Ord Streamly.Internal.FileSystem.Event.Linux.Event instance GHC.Show.Show Streamly.Internal.FileSystem.Event.Linux.Event -- | File system event notification API portable across Linux, macOS and -- Windows platforms. -- -- Note that recursive directory tree watch does not work reliably on -- Linux (see notes in the Linux module), therefore, recursive watch API -- is not provided in this module. However, you can use it from the -- platform specific modules. -- -- For platform specific APIs please see the following modules: -- --
-- >>> read = Socket.readWith defaultChunkSize ---- -- Pre-release read :: MonadIO m => Socket -> Stream m Word8 -- | Generate a byte stream from a socket using a buffer of the given size. -- -- Pre-release readWith :: MonadIO m => Int -> Socket -> Stream m Word8 -- | Read a stream of byte arrays from a socket. The maximum size of a -- single array is limited to defaultChunkSize. -- --
-- >>> readChunks = Socket.readChunksWith defaultChunkSize ---- -- Pre-release readChunks :: MonadIO m => Socket -> Stream m (Array Word8) -- | readChunksWith bufsize socket reads a stream of arrays from -- socket. The maximum size of a single array is limited to -- bufsize. -- -- Pre-release readChunksWith :: MonadIO m => Int -> Socket -> Stream m (Array Word8) -- | Unfolds a Socket into a byte stream. IO requests to the socket -- are performed in sizes of defaultChunkSize. reader :: MonadIO m => Unfold m Socket Word8 -- | Unfolds the tuple (bufsize, socket) into a byte stream, read -- requests to the socket are performed using buffers of -- bufsize. readerWith :: MonadIO m => Unfold m (Int, Socket) Word8 -- | Unfolds a socket into a stream of Word8 arrays. Requests to the -- socket are performed using a buffer of size defaultChunkSize. -- The size of arrays in the resulting stream are therefore less than or -- equal to defaultChunkSize. chunkReader :: MonadIO m => Unfold m Socket (Array Word8) -- | Unfold the tuple (bufsize, socket) into a stream of -- Word8 arrays. Read requests to the socket are performed using a -- buffer of size bufsize. The size of an array in the resulting -- stream is always less than or equal to bufsize. chunkReaderWith :: MonadIO m => Unfold m (Int, Socket) (Array Word8) -- | Write an Array to a socket. putChunk :: Unbox a => Socket -> Array a -> IO () -- | Write a byte stream to a socket. Accumulates the input in chunks of up -- to defaultChunkSize bytes before writing. -- --
-- >>> write = Socket.writeWith defaultChunkSize --write :: MonadIO m => Socket -> Fold m Word8 () -- | Write a byte stream to a socket. Accumulates the input in chunks of -- specified number of bytes before writing. writeWith :: MonadIO m => Int -> Socket -> Fold m Word8 () -- | Write a stream of arrays to a socket. Each array in the stream is -- written to the socket as a separate IO request. writeChunks :: (MonadIO m, Unbox a) => Socket -> Fold m (Array a) () -- | writeChunksWith bufsize socket writes a stream of arrays to -- socket after coalescing the adjacent arrays in chunks of -- bufsize. Multiple arrays are coalesed as long as the total -- size remains below the specified size. It never splits an array, if a -- single array is bigger than the specified size it emitted as it is. writeChunksWith :: (MonadIO m, Unbox a) => Int -> Socket -> Fold m (Array a) () -- | Write a stream of Maybe values. Keep buffering the Just -- values in an array. Write the array to the Handle as soon as -- a Nothing is encountered or the buffer size exceeds the -- specified limit. -- -- Pre-release writeMaybesWith :: MonadIO m => Int -> Socket -> Fold m (Maybe Word8) () -- | Write a stream of arrays to a handle. putChunks :: (MonadIO m, Unbox a) => Socket -> Stream m (Array a) -> m () -- | Like write but provides control over the write buffer. Output -- will be written to the IO device as soon as we collect the specified -- number of input elements. putBytesWith :: MonadIO m => Int -> Socket -> Stream m Word8 -> m () -- | Write a byte stream to a file handle. Combines the bytes in chunks of -- size up to defaultChunkSize before writing. Note that the write -- behavior depends on the IOMode and the current seek position -- of the handle. putBytes :: MonadIO m => Socket -> Stream m Word8 -> m () -- | Same as readWith -- | Deprecated: Please use readerWith instead readWithBufferOf :: MonadIO m => Unfold m (Int, Socket) Word8 -- | Same as chunkReaderWith -- | Deprecated: Please use chunkReaderWith instead readChunksWithBufferOf :: MonadIO m => Unfold m (Int, Socket) (Array Word8) -- | Same as writeWith -- | Deprecated: Please use writeWith instead writeWithBufferOf :: MonadIO m => Int -> Socket -> Fold m Word8 () -- | Same as writeChunksWith -- | Deprecated: Please use writeChunksWith instead writeChunksWithBufferOf :: (MonadIO m, Unbox a) => Int -> Socket -> Fold m (Array a) () -- | Combinators to build Inet/TCP clients and servers. module Streamly.Internal.Network.Inet.TCP -- | Start a TCP stream server that binds on the IPV4 address -- 0.0.0.0 and listens for TCP connections from remote hosts on -- the specified server port. The server generates a stream of connected -- sockets. -- --
-- >>> accept = TCP.acceptOnAddr (0,0,0,0) ---- -- Pre-release accept :: MonadIO m => PortNumber -> Stream m Socket -- | Like accept but binds on the localhost IPv4 address -- 127.0.0.1. The server can only be accessed from the local -- host, it cannot be accessed from other hosts on the network. -- --
-- >>> acceptLocal = TCP.acceptOnAddr (127,0,0,1) ---- -- Pre-release acceptLocal :: MonadIO m => PortNumber -> Stream m Socket -- | Like accept but binds on the specified IPv4 address. -- --
-- >>> acceptOnAddr = TCP.acceptOnAddrWith [] ---- -- Pre-release acceptOnAddr :: MonadIO m => (Word8, Word8, Word8, Word8) -> PortNumber -> Stream m Socket -- | Like acceptOnAddr but with the ability to specify a list of -- socket options. -- -- Pre-release acceptOnAddrWith :: MonadIO m => [(SocketOption, Int)] -> (Word8, Word8, Word8, Word8) -> PortNumber -> Stream m Socket -- | Like acceptorOnAddr but binds on the IPv4 address -- 0.0.0.0 i.e. on all IPv4 addresses/interfaces of the machine -- and listens for TCP connections on the specified port. -- --
-- >>> acceptor = Unfold.first (0,0,0,0) TCP.acceptorOnAddr --acceptor :: MonadIO m => Unfold m PortNumber Socket -- | Like acceptor but binds on the localhost IPv4 address -- 127.0.0.1. The server can only be accessed from the local -- host, it cannot be accessed from other hosts on the network. -- --
-- >>> acceptorLocal = Unfold.first (127,0,0,1) TCP.acceptorOnAddr --acceptorLocal :: MonadIO m => Unfold m PortNumber Socket acceptorWith :: MonadIO m => [(SocketOption, Int)] -> Unfold m PortNumber Socket -- | Unfold a tuple (ipAddr, port) into a stream of connected TCP -- sockets. ipAddr is the local IP address and port is -- the local port on which connections are accepted. acceptorOnAddr :: MonadIO m => Unfold m ((Word8, Word8, Word8, Word8), PortNumber) Socket acceptorOnAddrWith :: MonadIO m => [(SocketOption, Int)] -> Unfold m ((Word8, Word8, Word8, Word8), PortNumber) Socket -- | Connect to the specified IP address and port number. Returns a -- connected socket or throws an exception. connect :: (Word8, Word8, Word8, Word8) -> PortNumber -> IO Socket -- | Connect to a remote host using IP address and port and run the -- supplied action on the resulting socket. withConnectionM makes -- sure that the socket is closed on normal termination or in case of an -- exception. If closing the socket raises an exception, then this -- exception will be raised by withConnectionM. -- -- Pre-release withConnectionM :: (MonadMask m, MonadIO m) => (Word8, Word8, Word8, Word8) -> PortNumber -> (Socket -> m ()) -> m () -- | Transform an Unfold from a Socket to an unfold from a -- remote IP address and port. The resulting unfold opens a socket, uses -- it using the supplied unfold and then makes sure that the socket is -- closed on normal termination or in case of an exception. If closing -- the socket raises an exception, then this exception will be raised by -- usingConnection. -- -- Pre-release usingConnection :: (MonadCatch m, MonadAsync m) => Unfold m Socket a -> Unfold m ((Word8, Word8, Word8, Word8), PortNumber) a -- | Read a stream from the supplied IPv4 host address and port number. reader :: (MonadCatch m, MonadAsync m) => Unfold m ((Word8, Word8, Word8, Word8), PortNumber) Word8 -- | withConnection addr port act opens a connection to the -- specified IPv4 host address and port and passes the resulting socket -- handle to the computation act. The handle will be closed on -- exit from withConnection, whether by normal termination or by -- raising an exception. If closing the handle raises an exception, then -- this exception will be raised by withConnection rather than any -- exception raised by act. -- -- Pre-release withConnection :: (MonadCatch m, MonadAsync m) => (Word8, Word8, Word8, Word8) -> PortNumber -> (Socket -> Stream m a) -> Stream m a -- | Read a stream from the supplied IPv4 host address and port number. -- -- Pre-release read :: (MonadCatch m, MonadAsync m) => (Word8, Word8, Word8, Word8) -> PortNumber -> Stream m Word8 -- | Write a stream to the supplied IPv4 host address and port number. write :: (MonadIO m, MonadCatch m) => (Word8, Word8, Word8, Word8) -> PortNumber -> Fold m Word8 () -- | Like write but provides control over the write buffer. Output -- will be written to the IO device as soon as we collect the specified -- number of input elements. writeWithBufferOf :: (MonadIO m, MonadCatch m) => Int -> (Word8, Word8, Word8, Word8) -> PortNumber -> Fold m Word8 () -- | Write a stream to the supplied IPv4 host address and port number. -- -- Pre-release putBytes :: (MonadCatch m, MonadAsync m) => (Word8, Word8, Word8, Word8) -> PortNumber -> Stream m Word8 -> m () -- | Like write but provides control over the write buffer. Output -- will be written to the IO device as soon as we collect the specified -- number of input elements. -- -- Pre-release putBytesWithBufferOf :: (MonadCatch m, MonadAsync m) => Int -> (Word8, Word8, Word8, Word8) -> PortNumber -> Stream m Word8 -> m () -- | Write a stream of arrays to the supplied IPv4 host address and port -- number. writeChunks :: (MonadIO m, MonadCatch m) => (Word8, Word8, Word8, Word8) -> PortNumber -> Fold m (Array Word8) () -- | Write a stream of arrays to the supplied IPv4 host address and port -- number. -- -- Pre-release putChunks :: (MonadCatch m, MonadAsync m) => (Word8, Word8, Word8, Word8) -> PortNumber -> Stream m (Array Word8) -> m () -- | Send an input stream to a remote host and produce the output stream -- from the host. The server host just acts as a transformation function -- on the input stream. Both sending and receiving happen asynchronously. -- -- Pre-release pipeBytes :: (MonadAsync m, MonadCatch m) => (Word8, Word8, Word8, Word8) -> PortNumber -> Stream m Word8 -> Stream m Word8 -- | Deprecated: Use "acceptor" instead. acceptorOnPort :: MonadIO m => Unfold m PortNumber Socket -- | Deprecated: Use "acceptorLocal" instead. acceptorOnPortLocal :: MonadIO m => Unfold m PortNumber Socket module Streamly.Internal.Unicode.Char -- | Select alphabetic characters in the ascii character set. -- -- Pre-release isAsciiAlpha :: Char -> Bool data NormalizationMode -- | Canonical decomposition. NFD :: NormalizationMode -- | Compatibility decomposition. NFKD :: NormalizationMode -- | Canonical decomposition followed by canonical composition. NFC :: NormalizationMode -- | Compatibility decomposition followed by canonical composition. NFKC :: NormalizationMode normalize :: Monad m => NormalizationMode -> Stream m Char -> Stream m Char instance GHC.Enum.Enum Streamly.Internal.Unicode.Char.NormalizationMode instance GHC.Show.Show Streamly.Internal.Unicode.Char.NormalizationMode instance GHC.Classes.Eq Streamly.Internal.Unicode.Char.NormalizationMode module Streamly.Internal.Unicode.Utf8 -- | A space efficient, packed, unboxed Unicode container. data Utf8 pack :: String -> Utf8 unpack :: Utf8 -> String toArray :: Utf8 -> Array Word8 -- | Combinators to build Inet/IPv4/TCP clients and servers. -- --
-- >>> import qualified Streamly.Network.Inet.TCP as TCP ---- --
-- >>> import Control.Monad.Catch (finally) -- -- >>> import Data.Function ((&)) -- -- >>> import Network.Socket (Socket) -- -- >>> -- -- >>> import qualified Network.Socket as Net -- -- >>> import qualified Streamly.Data.Fold as Fold -- -- >>> import qualified Streamly.Data.Stream.Prelude as Stream -- -- >>> import qualified Streamly.Network.Inet.TCP as TCP -- -- >>> import qualified Streamly.Network.Socket as Socket -- -- >>> -- -- >>> :{ -- main :: IO () -- main = -- TCP.accept 8091 -- Stream IO Socket -- & Stream.parMapM id (handleExceptions echo) -- Stream IO () -- & Stream.fold Fold.drain -- IO () -- where -- echo :: Socket -> IO () -- echo sk = -- Socket.readChunksWith 32768 sk -- Stream IO (Array Word8) -- & Stream.fold (Socket.writeChunks sk) -- IO () -- handleExceptions :: (Socket -> IO ()) -> Socket -> IO () -- handleExceptions f sk = finally (f sk) (Net.close sk) -- :} --module Streamly.Network.Inet.TCP -- | Start a TCP stream server that binds on the IPV4 address -- 0.0.0.0 and listens for TCP connections from remote hosts on -- the specified server port. The server generates a stream of connected -- sockets. -- --
-- >>> accept = TCP.acceptOnAddr (0,0,0,0) ---- -- Pre-release accept :: MonadIO m => PortNumber -> Stream m Socket -- | Like accept but binds on the localhost IPv4 address -- 127.0.0.1. The server can only be accessed from the local -- host, it cannot be accessed from other hosts on the network. -- --
-- >>> acceptLocal = TCP.acceptOnAddr (127,0,0,1) ---- -- Pre-release acceptLocal :: MonadIO m => PortNumber -> Stream m Socket -- | Like accept but binds on the specified IPv4 address. -- --
-- >>> acceptOnAddr = TCP.acceptOnAddrWith [] ---- -- Pre-release acceptOnAddr :: MonadIO m => (Word8, Word8, Word8, Word8) -> PortNumber -> Stream m Socket -- | Like acceptOnAddr but with the ability to specify a list of -- socket options. -- -- Pre-release acceptOnAddrWith :: MonadIO m => [(SocketOption, Int)] -> (Word8, Word8, Word8, Word8) -> PortNumber -> Stream m Socket -- | Like acceptorOnAddr but binds on the IPv4 address -- 0.0.0.0 i.e. on all IPv4 addresses/interfaces of the machine -- and listens for TCP connections on the specified port. -- --
-- >>> acceptor = Unfold.first (0,0,0,0) TCP.acceptorOnAddr --acceptor :: MonadIO m => Unfold m PortNumber Socket -- | Like acceptor but binds on the localhost IPv4 address -- 127.0.0.1. The server can only be accessed from the local -- host, it cannot be accessed from other hosts on the network. -- --
-- >>> acceptorLocal = Unfold.first (127,0,0,1) TCP.acceptorOnAddr --acceptorLocal :: MonadIO m => Unfold m PortNumber Socket -- | Unfold a tuple (ipAddr, port) into a stream of connected TCP -- sockets. ipAddr is the local IP address and port is -- the local port on which connections are accepted. acceptorOnAddr :: MonadIO m => Unfold m ((Word8, Word8, Word8, Word8), PortNumber) Socket -- | Connect to the specified IP address and port number. Returns a -- connected socket or throws an exception. connect :: (Word8, Word8, Word8, Word8) -> PortNumber -> IO Socket -- | Deprecated: Use "acceptor" instead. acceptorOnPort :: MonadIO m => Unfold m PortNumber Socket -- | Deprecated: Use "acceptorLocal" instead. acceptorOnPortLocal :: MonadIO m => Unfold m PortNumber Socket -- | This module provides socket based streaming APIs to to receive -- connections from remote hosts, and to read and write from and to -- network sockets. -- -- For basic socket types and non-streaming operations please consult the -- Network.Socket module of the network package. -- --
-- >>> :set -XFlexibleContexts -- -- >>> -- -- >>> import Data.Function ((&)) -- -- >>> import Network.Socket -- -- >>> import Streamly.Network.Socket (SockSpec(..)) -- -- >>> -- -- >>> import qualified Streamly.Data.Fold as Fold -- -- >>> import qualified Streamly.Data.Stream.Prelude as Stream -- -- >>> import qualified Streamly.Network.Socket as Socket -- -- >>> -- -- >>> :{ -- main :: IO () -- main = do -- let spec = SockSpec -- { sockFamily = AF_INET -- , sockType = Stream -- , sockProto = defaultProtocol -- , sockOpts = [] -- } -- addr = SockAddrInet 8090 (tupleToHostAddress (0,0,0,0)) -- in server spec addr -- where -- server spec addr = -- Socket.accept maxListenQueue spec addr -- & Stream.parMapM (Stream.eager True) (Socket.forSocketM echo) -- & Stream.fold Fold.drain -- echo sk = -- Socket.readChunks sk -- Stream IO (Array Word8) -- & Stream.fold (Socket.writeChunks sk) -- IO () -- :} ---- --
-- >>> import qualified Streamly.Network.Socket as Socket ---- --
-- >>> read = Socket.readWith defaultChunkSize ---- -- Pre-release read :: MonadIO m => Socket -> Stream m Word8 -- | Generate a byte stream from a socket using a buffer of the given size. -- -- Pre-release readWith :: MonadIO m => Int -> Socket -> Stream m Word8 -- | Read a stream of byte arrays from a socket. The maximum size of a -- single array is limited to defaultChunkSize. -- --
-- >>> readChunks = Socket.readChunksWith defaultChunkSize ---- -- Pre-release readChunks :: MonadIO m => Socket -> Stream m (Array Word8) -- | readChunksWith bufsize socket reads a stream of arrays from -- socket. The maximum size of a single array is limited to -- bufsize. -- -- Pre-release readChunksWith :: MonadIO m => Int -> Socket -> Stream m (Array Word8) -- | Unfolds a Socket into a byte stream. IO requests to the socket -- are performed in sizes of defaultChunkSize. reader :: MonadIO m => Unfold m Socket Word8 -- | Unfolds the tuple (bufsize, socket) into a byte stream, read -- requests to the socket are performed using buffers of -- bufsize. readerWith :: MonadIO m => Unfold m (Int, Socket) Word8 -- | Unfolds a socket into a stream of Word8 arrays. Requests to the -- socket are performed using a buffer of size defaultChunkSize. -- The size of arrays in the resulting stream are therefore less than or -- equal to defaultChunkSize. chunkReader :: MonadIO m => Unfold m Socket (Array Word8) -- | Unfold the tuple (bufsize, socket) into a stream of -- Word8 arrays. Read requests to the socket are performed using a -- buffer of size bufsize. The size of an array in the resulting -- stream is always less than or equal to bufsize. chunkReaderWith :: MonadIO m => Unfold m (Int, Socket) (Array Word8) -- | Write an Array to a socket. putChunk :: Unbox a => Socket -> Array a -> IO () -- | Write a byte stream to a socket. Accumulates the input in chunks of up -- to defaultChunkSize bytes before writing. -- --
-- >>> write = Socket.writeWith defaultChunkSize --write :: MonadIO m => Socket -> Fold m Word8 () -- | Write a byte stream to a socket. Accumulates the input in chunks of -- specified number of bytes before writing. writeWith :: MonadIO m => Int -> Socket -> Fold m Word8 () -- | Write a stream of arrays to a socket. Each array in the stream is -- written to the socket as a separate IO request. writeChunks :: (MonadIO m, Unbox a) => Socket -> Fold m (Array a) () -- | writeChunksWith bufsize socket writes a stream of arrays to -- socket after coalescing the adjacent arrays in chunks of -- bufsize. Multiple arrays are coalesed as long as the total -- size remains below the specified size. It never splits an array, if a -- single array is bigger than the specified size it emitted as it is. writeChunksWith :: (MonadIO m, Unbox a) => Int -> Socket -> Fold m (Array a) () -- | forSocketM action socket runs the monadic computation -- action passing the socket handle to it. The handle will be -- closed on exit from forSocketM, whether by normal termination -- or by raising an exception. If closing the handle raises an exception, -- then this exception will be raised by forSocketM rather than -- any exception raised by action. forSocketM :: (MonadMask m, MonadIO m) => (Socket -> m ()) -> Socket -> m () -- | Deprecated: Please use getChunk instead readChunk :: Int -> Socket -> IO (Array Word8) -- | Deprecated: Please use putChunk instead writeChunk :: Unbox a => Socket -> Array a -> IO () -- | Same as readWith -- | Deprecated: Please use readerWith instead readWithBufferOf :: MonadIO m => Unfold m (Int, Socket) Word8 -- | Same as chunkReaderWith -- | Deprecated: Please use chunkReaderWith instead readChunksWithBufferOf :: MonadIO m => Unfold m (Int, Socket) (Array Word8) -- | Same as writeWith -- | Deprecated: Please use writeWith instead writeWithBufferOf :: MonadIO m => Int -> Socket -> Fold m Word8 () -- | Same as writeChunksWith -- | Deprecated: Please use writeChunksWith instead writeChunksWithBufferOf :: (MonadIO m, Unbox a) => Int -> Socket -> Fold m (Array a) () -- | To run examples in this module: -- --
-- >>> import qualified Streamly.Data.Fold as Fold -- -- >>> import qualified Streamly.Prelude as Stream ---- -- We will add some more imports in the examples as needed. -- -- For effectful streams we will use the following IO action that blocks -- for n seconds: -- --
-- >>> import Control.Concurrent (threadDelay) -- -- >>> :{ -- delay n = do -- threadDelay (n * 1000000) -- sleep for n seconds -- putStrLn (show n ++ " sec") -- print "n sec" -- return n -- IO Int -- :} ---- --
-- >>> delay 1 -- 1 sec -- 1 ---- --
-- >>> import Streamly.Prelude (SerialT, cons, consM, nil) -- -- >>> stream = 1 `cons` 2 `cons` nil :: SerialT IO Int -- -- >>> Stream.toList stream -- IO [Int] -- [1,2] ---- -- consM constructs a stream from effectful actions: -- --
-- >>> stream = delay 1 `consM` delay 2 `consM` nil -- -- >>> Stream.toList stream -- 1 sec -- 2 sec -- [1,2] ---- --
-- >>> import Data.Function ((&)) ---- --
-- > :{ -- Stream.repeatM getLine -- SerialT IO String -- & Stream.mapM putStrLn -- SerialT IO () -- & Stream.drain -- IO () -- :} ---- -- This is a console echo program. It is an example of a declarative loop -- written using streaming combinators. Compare it with an imperative -- while loop. -- -- Hopefully, this gives you an idea how we can program declaratively by -- representing loops using streams. In this module, you can find all -- Data.List like functions and many more powerful combinators to -- perform common programming tasks. Also see -- Streamly.Internal.Data.Stream.IsStream module for many more -- Pre-release combinators. See the -- https://github.com/composewell/streamly-examples repository for -- many more real world examples of stream programming. -- --
-- repeatM :: (IsStream t, MonadAsync m) => m a -> t m a ---- -- t is the stream type, m is the underlying -- Monad of the stream (e.g. IO) and a is the type of -- elements in the stream (e.g. Int). -- -- Stream elimination combinators accept a SerialT type instead of -- a polymorphic type to force a concrete monomorphic type by default, -- reducing type errors. That's why in the console echo example above the -- stream type is SerialT. -- --
-- drain :: Monad m => SerialT m a -> m () ---- -- We can force a certain stream type in polymorphic code by using -- "Stream Type Adaptors". For example, to force AsyncT: -- --
-- >>> Stream.drain $ Stream.fromAsync $ Stream.replicateM 10 $ delay 1 -- ... ---- --
-- >>> stream1 = Stream.fromListM [delay 3, delay 4] -- -- >>> stream2 = Stream.fromListM [delay 1, delay 2] -- -- >>> Stream.toList $ stream1 `parallel` stream2 -- ... ---- -- We can chain the operations to combine more than two streams: -- --
-- >>> stream3 = Stream.fromListM [delay 1, delay 2] -- -- >>> Stream.toList $ stream1 `parallel` stream2 `parallel` stream3 -- ... ---- -- Concurrent generation (consM) and concurrent merging of streams -- is the fundamental basis of all concurrency in streamly. -- --
-- import qualified Streamly.Network.Inet.TCP as TCP -- import qualified Streamly.Network.Socket as Socket -- -- Stream.unfold TCP.acceptOnPort 8090 -- & Stream.concatMapWith Stream.parallel (Stream.unfold Socket.read) ---- -- See the streamly-examples repository for a full working -- example. -- --
-- >>> stream = delay 2 `consM` delay 1 `consM` nil -- -- >>> Stream.toList stream -- IO [Int] -- 2 sec -- 1 sec -- [2,1] ---- -- AsyncT executes the actions concurrently, so the total delay is -- max 2 1 = 2 seconds: -- --
-- >>> Stream.toList $ Stream.fromAsync stream -- IO [Int] -- 1 sec -- 2 sec -- [1,2] ---- -- AsyncT produces the results in the order in which execution -- finishes. Notice the order of elements in the list above, it is not -- the same as the order of actions in the stream. -- -- AheadT is similar to AsyncT but the order of results is -- the same as the order of actions, even though they execute -- concurrently: -- --
-- >>> Stream.toList $ Stream.fromAhead stream -- IO [Int] -- 1 sec -- 2 sec -- [2,1] ---- --
-- >>> stream1 = Stream.fromListM [delay 1, delay 2] -- -- >>> stream2 = Stream.fromListM [delay 3, delay 4] -- -- >>> Stream.toList $ stream1 <> stream2 -- 1 sec -- 2 sec -- 3 sec -- 4 sec -- [1,2,3,4] ---- -- For WSerialT, <> has an interleaving behavior i.e. -- it executes one action from the first stream and then one action from -- the second stream and so on: -- --
-- >>> Stream.toList $ Stream.fromWSerial $ stream1 <> stream2 -- 1 sec -- 3 sec -- 2 sec -- 4 sec -- [1,3,2,4] ---- -- The <> operation of SerialT and WSerialT is -- the same as serial and wSerial respectively. The -- serial combinator combines two streams of any type in the same -- way as a serial stream combines. -- --
-- >>> Stream.drain $ Stream.replicateM 10 $ delay 1 -- ... ---- -- We can use the fromAsync combinator to force the argument -- stream to be of AsyncT type, replicateM in the following -- example executes the replicated actions concurrently, thus taking only -- 1 second: -- --
-- >>> Stream.drain $ Stream.fromAsync $ Stream.replicateM 10 $ delay 1 -- ... ---- -- We can use mapM to map an action concurrently: -- --
-- >>> f x = delay 1 >> return (x + 1) -- -- >>> Stream.toList $ Stream.fromAhead $ Stream.mapM f $ Stream.fromList [1..3] -- ... -- [2,3,4] ---- -- fromAhead forces mapM to happen in AheadT style, thus -- all three actions take only one second even though each individual -- action blocks for a second. -- -- See the documentation of individual combinators to check if it is -- concurrent or not. The concurrent combinators necessarily have a -- MonadAsync m constraint. However, a MonadAsync m -- constraint does not necessarily mean that the combinator is -- concurrent. -- --
-- Stream.fromAsync $ ... concurrent combinator here ... $ Stream.fromSerial $ ... ---- --
-- > toList $ 1 `cons` 2 `cons` 3 `cons` nil -- [1,2,3] --cons :: IsStream t => a -> t m a -> t m a infixr 5 `cons` -- | Operator equivalent of cons. -- --
-- > toList $ 1 .: 2 .: 3 .: nil -- [1,2,3] --(.:) :: IsStream t => a -> t m a -> t m a infixr 5 .: -- | Constructs a stream by adding a monadic action at the head of an -- existing stream. For example: -- --
-- > toList $ getLine `consM` getLine `consM` nil -- hello -- world -- ["hello","world"] ---- -- Concurrent (do not use fromParallel to construct infinite -- streams) consM :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a infixr 5 `consM` -- | Operator equivalent of consM. We can read it as "parallel -- colon" to remember that | comes before :. -- --
-- > toList $ getLine |: getLine |: nil -- hello -- world -- ["hello","world"] ---- --
-- let delay = threadDelay 1000000 >> print 1 -- drain $ fromSerial $ delay |: delay |: delay |: nil -- drain $ fromParallel $ delay |: delay |: delay |: nil ---- -- Concurrent (do not use fromParallel to construct infinite -- streams) (|:) :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a infixr 5 |: -- | Convert an Unfold into a stream by supplying it an input seed. -- --
-- >>> Stream.drain $ Stream.unfold Unfold.replicateM (3, putStrLn "hello") -- hello -- hello -- hello ---- -- Since: 0.7.0 unfold :: (IsStream t, Monad m) => Unfold m a b -> a -> t m b -- |
-- >>> :{ -- unfoldr step s = -- case step s of -- Nothing -> Stream.nil -- Just (a, b) -> a `Stream.cons` unfoldr step b -- :} ---- -- Build a stream by unfolding a pure step function step -- starting from a seed s. The step function returns the next -- element in the stream and the next seed value. When it is done it -- returns Nothing and the stream ends. For example, -- --
-- >>> :{ -- let f b = -- if b > 2 -- then Nothing -- else Just (b, b + 1) -- in Stream.toList $ Stream.unfoldr f 0 -- :} -- [0,1,2] --unfoldr :: (Monad m, IsStream t) => (b -> Maybe (a, b)) -> b -> t m a -- | Build a stream by unfolding a monadic step function starting -- from a seed. The step function returns the next element in the stream -- and the next seed value. When it is done it returns Nothing and -- the stream ends. For example, -- --
-- >>> :{ -- let f b = -- if b > 2 -- then return Nothing -- else return (Just (b, b + 1)) -- in Stream.toList $ Stream.unfoldrM f 0 -- :} -- [0,1,2] ---- -- When run concurrently, the next unfold step can run concurrently with -- the processing of the output of the previous step. Note that more than -- one step cannot run concurrently as the next step depends on the -- output of the previous step. -- --
-- >>> :{ -- let f b = -- if b > 2 -- then return Nothing -- else threadDelay 1000000 >> return (Just (b, b + 1)) -- in Stream.toList $ Stream.delay 1 $ Stream.fromAsync $ Stream.unfoldrM f 0 -- :} -- [0,1,2] ---- -- Concurrent -- -- Since: 0.1.0 unfoldrM :: forall t m b a. (IsStream t, MonadAsync m) => (b -> m (Maybe (a, b))) -> b -> t m a -- |
-- fromPure a = a `cons` nil ---- -- Create a singleton stream from a pure value. -- -- The following holds in monadic streams, but not in Zip streams: -- --
-- fromPure = pure -- fromPure = fromEffect . pure ---- -- In Zip applicative streams fromPure is not the same as -- pure because in that case pure is equivalent to -- repeat instead. fromPure and pure are equally -- efficient, in other cases fromPure may be slightly more -- efficient than the other equivalent definitions. -- -- Since: 0.8.0 (Renamed yield to fromPure) fromPure :: IsStream t => a -> t m a -- |
-- fromEffect m = m `consM` nil ---- -- Create a singleton stream from a monadic action. -- --
-- > Stream.toList $ Stream.fromEffect getLine -- hello -- ["hello"] ---- -- Since: 0.8.0 (Renamed yieldM to fromEffect) fromEffect :: (Monad m, IsStream t) => m a -> t m a -- | Generate an infinite stream by repeating a pure value. repeat :: (IsStream t, Monad m) => a -> t m a -- |
-- >>> repeatM = fix . consM -- -- >>> repeatM = cycle1 . fromEffect ---- -- Generate a stream by repeatedly executing a monadic action forever. -- --
-- >>> :{ -- repeatAsync = -- Stream.repeatM (threadDelay 1000000 >> print 1) -- & Stream.take 10 -- & Stream.fromAsync -- & Stream.drain -- :} ---- -- Concurrent, infinite (do not use with fromParallel) repeatM :: (IsStream t, MonadAsync m) => m a -> t m a -- |
-- >>> replicate n = Stream.take n . Stream.repeat ---- -- Generate a stream of length n by repeating a value n -- times. replicate :: (IsStream t, Monad m) => Int -> a -> t m a -- |
-- >>> replicateM n = Stream.take n . Stream.repeatM ---- -- Generate a stream by performing a monadic action n times. -- Same as: -- --
-- >>> pr n = threadDelay 1000000 >> print n ---- -- This runs serially and takes 3 seconds: -- --
-- >>> Stream.drain $ Stream.fromSerial $ Stream.replicateM 3 $ pr 1 -- 1 -- 1 -- 1 ---- -- This runs concurrently and takes just 1 second: -- --
-- >>> Stream.drain $ Stream.fromAsync $ Stream.replicateM 3 $ pr 1 -- 1 -- 1 -- 1 ---- -- Concurrent replicateM :: forall t m a. (IsStream t, MonadAsync m) => Int -> m a -> t m a -- | Types that can be enumerated as a stream. The operations in this type -- class are equivalent to those in the Enum type class, except -- that these generate a stream instead of a list. Use the functions in -- Streamly.Internal.Data.Stream.Enumeration module to define new -- instances. class Enum a => Enumerable a -- | enumerateFrom from generates a stream starting with the -- element from, enumerating up to maxBound when the type -- is Bounded or generating an infinite stream when the type is -- not Bounded. -- --
-- >>> Stream.toList $ Stream.take 4 $ Stream.enumerateFrom (0 :: Int) -- [0,1,2,3] ---- -- For Fractional types, enumeration is numerically stable. -- However, no overflow or underflow checks are performed. -- --
-- >>> Stream.toList $ Stream.take 4 $ Stream.enumerateFrom 1.1 -- [1.1,2.1,3.1,4.1] --enumerateFrom :: (Enumerable a, IsStream t, Monad m) => a -> t m a -- | Generate a finite stream starting with the element from, -- enumerating the type up to the value to. If to is -- smaller than from then an empty stream is returned. -- --
-- >>> Stream.toList $ Stream.enumerateFromTo 0 4 -- [0,1,2,3,4] ---- -- For Fractional types, the last element is equal to the -- specified to value after rounding to the nearest integral -- value. -- --
-- >>> Stream.toList $ Stream.enumerateFromTo 1.1 4 -- [1.1,2.1,3.1,4.1] -- -- >>> Stream.toList $ Stream.enumerateFromTo 1.1 4.6 -- [1.1,2.1,3.1,4.1,5.1] --enumerateFromTo :: (Enumerable a, IsStream t, Monad m) => a -> a -> t m a -- | enumerateFromThen from then generates a stream whose first -- element is from, the second element is then and the -- successive elements are in increments of then - from. -- Enumeration can occur downwards or upwards depending on whether -- then comes before or after from. For Bounded -- types the stream ends when maxBound is reached, for unbounded -- types it keeps enumerating infinitely. -- --
-- >>> Stream.toList $ Stream.take 4 $ Stream.enumerateFromThen 0 2 -- [0,2,4,6] -- -- >>> Stream.toList $ Stream.take 4 $ Stream.enumerateFromThen 0 (-2) -- [0,-2,-4,-6] --enumerateFromThen :: (Enumerable a, IsStream t, Monad m) => a -> a -> t m a -- | enumerateFromThenTo from then to generates a finite stream -- whose first element is from, the second element is -- then and the successive elements are in increments of -- then - from up to to. Enumeration can occur -- downwards or upwards depending on whether then comes before -- or after from. -- --
-- >>> Stream.toList $ Stream.enumerateFromThenTo 0 2 6 -- [0,2,4,6] -- -- >>> Stream.toList $ Stream.enumerateFromThenTo 0 (-2) (-6) -- [0,-2,-4,-6] --enumerateFromThenTo :: (Enumerable a, IsStream t, Monad m) => a -> a -> a -> t m a -- |
-- enumerate = enumerateFrom minBound ---- -- Enumerate a Bounded type from its minBound to -- maxBound enumerate :: (IsStream t, Monad m, Bounded a, Enumerable a) => t m a -- |
-- enumerateTo = enumerateFromTo minBound ---- -- Enumerate a Bounded type from its minBound to specified -- value. enumerateTo :: (IsStream t, Monad m, Bounded a, Enumerable a) => a -> t m a -- |
-- >>> iterate f x = x `Stream.cons` iterate f x ---- -- Generate an infinite stream with x as the first element and -- each successive element derived by applying the function f on -- the previous element. -- --
-- >>> Stream.toList $ Stream.take 5 $ Stream.iterate (+1) 1 -- [1,2,3,4,5] --iterate :: (IsStream t, Monad m) => (a -> a) -> a -> t m a -- |
-- >>> iterateM f m = m >>= \a -> return a `Stream.consM` iterateM f (f a) ---- -- Generate an infinite stream with the first element generated by the -- action m and each successive element derived by applying the -- monadic function f on the previous element. -- --
-- >>> pr n = threadDelay 1000000 >> print n -- -- >>> :{ -- Stream.iterateM (\x -> pr x >> return (x + 1)) (return 0) -- & Stream.take 3 -- & Stream.fromSerial -- & Stream.toList -- :} -- 0 -- 1 -- [0,1,2] ---- -- When run concurrently, the next iteration can run concurrently with -- the processing of the previous iteration. Note that more than one -- iteration cannot run concurrently as the next iteration depends on the -- output of the previous iteration. -- --
-- >>> :{ -- Stream.iterateM (\x -> pr x >> return (x + 1)) (return 0) -- & Stream.delay 1 -- & Stream.take 3 -- & Stream.fromAsync -- & Stream.toList -- :} -- 0 -- 1 -- ... ---- -- Concurrent -- -- Since: 0.1.2 -- -- Since: 0.7.0 (signature change) iterateM :: forall t m a. (IsStream t, MonadAsync m) => (a -> m a) -> m a -> t m a -- |
-- >>> fromIndices f = fmap f $ Stream.enumerateFrom 0 -- -- >>> fromIndices f = let g i = f i `Stream.cons` g (i + 1) in g 0 ---- -- Generate an infinite stream, whose values are the output of a function -- f applied on the corresponding index. Index starts at 0. -- --
-- >>> Stream.toList $ Stream.take 5 $ Stream.fromIndices id -- [0,1,2,3,4] --fromIndices :: (IsStream t, Monad m) => (Int -> a) -> t m a -- |
-- >>> fromIndicesM f = Stream.mapM f $ Stream.enumerateFrom 0 -- -- >>> fromIndicesM f = let g i = f i `Stream.consM` g (i + 1) in g 0 ---- -- Generate an infinite stream, whose values are the output of a monadic -- function f applied on the corresponding index. Index starts -- at 0. -- -- Concurrent fromIndicesM :: forall t m a. (IsStream t, MonadAsync m) => (Int -> m a) -> t m a -- |
-- fromList = foldr cons nil ---- -- Construct a stream from a list of pure values. This is more efficient -- than fromFoldable for serial streams. fromList :: (Monad m, IsStream t) => [a] -> t m a -- |
-- >>> fromListM = Stream.fromFoldableM -- -- >>> fromListM = Stream.sequence . Stream.fromList -- -- >>> fromListM = Stream.mapM id . Stream.fromList -- -- >>> fromListM = Prelude.foldr Stream.consM Stream.nil ---- -- Construct a stream from a list of monadic actions. This is more -- efficient than fromFoldableM for serial streams. fromListM :: (MonadAsync m, IsStream t) => [m a] -> t m a -- |
-- >>> fromFoldable = Prelude.foldr Stream.cons Stream.nil ---- -- Construct a stream from a Foldable containing pure values: fromFoldable :: (IsStream t, Foldable f) => f a -> t m a -- |
-- >>> fromFoldableM = Prelude.foldr Stream.consM Stream.nil ---- -- Construct a stream from a Foldable containing monadic actions. -- --
-- >>> pr n = threadDelay 1000000 >> print n -- -- >>> Stream.drain $ Stream.fromSerial $ Stream.fromFoldableM $ map pr [1,2,3] -- 1 -- 2 -- 3 ---- --
-- >>> Stream.drain $ Stream.fromAsync $ Stream.fromFoldableM $ map pr [1,2,3] -- ... -- ... -- ... ---- -- Concurrent (do not use with fromParallel on infinite -- containers) fromFoldableM :: (IsStream t, MonadAsync m, Foldable f) => f (m a) -> t m a -- | Fold a stream using the supplied left Fold and reducing the -- resulting expression strictly at each step. The behavior is similar to -- foldl'. A Fold can terminate early without consuming -- the full stream. See the documentation of individual Folds for -- termination behavior. -- --
-- >>> Stream.fold Fold.sum (Stream.enumerateFromTo 1 100) -- 5050 ---- -- Folds never fail, therefore, they produce a default value even when no -- input is provided. It means we can always fold an empty stream and get -- a valid result. For example: -- --
-- >>> Stream.fold Fold.sum Stream.nil -- 0 ---- -- However, foldMany on an empty stream results in an empty -- stream. Therefore, Stream.fold f is not the same as -- Stream.head . Stream.foldMany f. -- --
-- fold f = Stream.parse (Parser.fromFold f) --fold :: Monad m => Fold m a b -> SerialT m a -> m b -- | Decompose a stream into its head and tail. If the stream is empty, -- returns Nothing. If the stream is non-empty, returns Just -- (a, ma), where a is the head of the stream and -- ma its tail. -- -- This can be used to do pretty much anything in an imperative manner, -- as it just breaks down the stream into individual elements and we can -- loop over them as we deem fit. For example, this can be used to -- convert a streamly stream into other stream types. -- -- All the folds in this module can be expressed in terms of -- uncons, however, this is generally less efficient than specific -- folds because it takes apart the stream one element at a time, -- therefore, does not take adavantage of stream fusion. uncons :: (IsStream t, Monad m) => SerialT m a -> m (Maybe (a, t m a)) -- |
-- tail = fmap (fmap snd) . Stream.uncons ---- -- Extract all but the first element of the stream, if any. tail :: (IsStream t, Monad m) => SerialT m a -> m (Maybe (t m a)) -- | Extract all but the last element of the stream, if any. init :: (IsStream t, Monad m) => SerialT m a -> m (Maybe (t m a)) -- | Right associative/lazy pull fold. foldrM build final stream -- constructs an output structure using the step function build. -- build is invoked with the next input element and the -- remaining (lazy) tail of the output structure. It builds a lazy output -- expression using the two. When the "tail structure" in the output -- expression is evaluated it calls build again thus lazily -- consuming the input stream until either the output expression -- built by build is free of the "tail" or the input is -- exhausted in which case final is used as the terminating case -- for the output structure. For more details see the description in the -- previous section. -- -- Example, determine if any element is odd in a stream: -- --
-- >>> Stream.foldrM (\x xs -> if odd x then return True else xs) (return False) $ Stream.fromList (2:4:5:undefined) -- True ---- -- Since: 0.7.0 (signature changed) -- -- Since: 0.2.0 (signature changed) -- -- Since: 0.1.0 foldrM :: Monad m => (a -> m b -> m b) -> m b -> SerialT m a -> m b -- | Right fold, lazy for lazy monads and pure streams, and strict for -- strict monads. -- -- Please avoid using this routine in strict monads like IO unless you -- need a strict right fold. This is provided only for use in lazy monads -- (e.g. Identity) or pure streams. Note that with this signature it is -- not possible to implement a lazy foldr when the monad m is -- strict. In that case it would be strict in its accumulator and -- therefore would necessarily consume all its input. foldr :: Monad m => (a -> b -> b) -> b -> SerialT m a -> m b -- | Left associative/strict push fold. foldl' reduce initial -- stream invokes reduce with the accumulator and the next -- input in the input stream, using initial as the initial value -- of the current value of the accumulator. When the input is exhausted -- the current value of the accumulator is returned. Make sure to use a -- strict data structure for accumulator to not build unnecessary lazy -- expressions unless that's what you want. See the previous section for -- more details. foldl' :: Monad m => (b -> a -> b) -> b -> SerialT m a -> m b -- | Strict left fold, for non-empty streams, using first element as the -- starting value. Returns Nothing if the stream is empty. foldl1' :: Monad m => (a -> a -> a) -> SerialT m a -> m (Maybe a) -- | Like foldl' but with a monadic step function. -- -- Since: 0.2.0 -- -- Since: 0.8.0 (signature change) foldlM' :: Monad m => (b -> a -> m b) -> m b -> SerialT m a -> m b -- |
-- drain = mapM_ (\_ -> return ()) -- drain = Stream.fold Fold.drain ---- -- Run a stream, discarding the results. By default it interprets the -- stream as SerialT, to run other types of streams use the type -- adapting combinators for example Stream.drain . -- fromAsync. drain :: Monad m => SerialT m a -> m () -- | Extract the last element of the stream, if any. -- --
-- last xs = xs !! (Stream.length xs - 1) -- last = Stream.fold Fold.last --last :: Monad m => SerialT m a -> m (Maybe a) -- | Determine the length of the stream. length :: Monad m => SerialT m a -> m Int -- | Determine the sum of all elements of a stream of numbers. Returns -- 0 when the stream is empty. Note that this is not numerically -- stable for floating point numbers. -- --
-- sum = Stream.fold Fold.sum --sum :: (Monad m, Num a) => SerialT m a -> m a -- | Determine the product of all elements of a stream of numbers. Returns -- 1 when the stream is empty. -- --
-- product = Stream.fold Fold.product --product :: (Monad m, Num a) => SerialT m a -> m a -- | Determine the maximum element in a stream using the supplied -- comparison function. -- --
-- maximumBy = Stream.fold Fold.maximumBy --maximumBy :: Monad m => (a -> a -> Ordering) -> SerialT m a -> m (Maybe a) -- |
-- maximum = maximumBy compare -- maximum = Stream.fold Fold.maximum ---- -- Determine the maximum element in a stream. maximum :: (Monad m, Ord a) => SerialT m a -> m (Maybe a) -- | Determine the minimum element in a stream using the supplied -- comparison function. -- --
-- minimumBy = Stream.fold Fold.minimumBy --minimumBy :: Monad m => (a -> a -> Ordering) -> SerialT m a -> m (Maybe a) -- |
-- minimum = minimumBy compare -- minimum = Stream.fold Fold.minimum ---- -- Determine the minimum element in a stream. minimum :: (Monad m, Ord a) => SerialT m a -> m (Maybe a) -- | Ensures that all the elements of the stream are identical and then -- returns that unique element. the :: (Eq a, Monad m) => SerialT m a -> m (Maybe a) -- |
-- drainN n = Stream.drain . Stream.take n -- drainN n = Stream.fold (Fold.take n Fold.drain) ---- -- Run maximum up to n iterations of a stream. drainN :: Monad m => Int -> SerialT m a -> m () -- |
-- drainWhile p = Stream.drain . Stream.takeWhile p ---- -- Run a stream as long as the predicate holds true. drainWhile :: Monad m => (a -> Bool) -> SerialT m a -> m () -- | Lookup the element at the given index. (!!) :: Monad m => SerialT m a -> Int -> m (Maybe a) -- | Extract the first element of the stream, if any. -- --
-- head = (!! 0) -- head = Stream.fold Fold.one --head :: Monad m => SerialT m a -> m (Maybe a) -- | Returns the first element that satisfies the given predicate. -- --
-- findM = Stream.fold Fold.findM --findM :: Monad m => (a -> m Bool) -> SerialT m a -> m (Maybe a) -- | Like findM but with a non-monadic predicate. -- --
-- find p = findM (return . p) -- find = Stream.fold Fold.find --find :: Monad m => (a -> Bool) -> SerialT m a -> m (Maybe a) -- | In a stream of (key-value) pairs (a, b), return the value -- b of the first pair where the key equals the given value -- a. -- --
-- lookup = snd <$> Stream.find ((==) . fst) -- lookup = Stream.fold Fold.lookup --lookup :: (Monad m, Eq a) => a -> SerialT m (a, b) -> m (Maybe b) -- | Returns the first index that satisfies the given predicate. -- --
-- findIndex = Stream.fold Fold.findIndex --findIndex :: Monad m => (a -> Bool) -> SerialT m a -> m (Maybe Int) -- | Returns the first index where a given value is found in the stream. -- --
-- elemIndex a = Stream.findIndex (== a) --elemIndex :: (Monad m, Eq a) => a -> SerialT m a -> m (Maybe Int) -- | Determine whether the stream is empty. -- --
-- null = Stream.fold Fold.null --null :: Monad m => SerialT m a -> m Bool -- | Determine whether an element is present in the stream. -- --
-- elem = Stream.fold Fold.elem --elem :: (Monad m, Eq a) => a -> SerialT m a -> m Bool -- | Determine whether an element is not present in the stream. -- --
-- notElem = Stream.fold Fold.length --notElem :: (Monad m, Eq a) => a -> SerialT m a -> m Bool -- | Determine whether all elements of a stream satisfy a predicate. -- --
-- all = Stream.fold Fold.all --all :: Monad m => (a -> Bool) -> SerialT m a -> m Bool -- | Determine whether any of the elements of a stream satisfy a predicate. -- --
-- any = Stream.fold Fold.any --any :: Monad m => (a -> Bool) -> SerialT m a -> m Bool -- | Determines if all elements of a boolean stream are True. -- --
-- and = Stream.fold Fold.and --and :: Monad m => SerialT m Bool -> m Bool -- | Determines whether at least one element of a boolean stream is True. -- --
-- or = Stream.fold Fold.or --or :: Monad m => SerialT m Bool -> m Bool -- |
-- toList = Stream.foldr (:) [] ---- -- Convert a stream into a list in the underlying monad. The list can be -- consumed lazily in a lazy monad (e.g. Identity). In a strict -- monad (e.g. IO) the whole list is generated and buffered before it can -- be consumed. -- -- Warning! working on large lists accumulated as buffers in -- memory could be very inefficient, consider using Streamly.Array -- instead. toList :: Monad m => SerialT m a -> m [a] -- | Parallel fold application operator; applies a fold function t m a -- -> m b to a stream t m a concurrently; The the input -- stream is evaluated asynchronously in an independent thread yielding -- elements to a buffer and the folding action runs in another thread -- consuming the input from the buffer. -- -- If you read the signature as (t m a -> m b) -> (t m a -> -- m b) you can look at it as a transformation that converts a fold -- function to a buffered concurrent fold function. -- -- The . at the end of the operator is a mnemonic for -- termination of the stream. -- -- In the example below, each stage introduces a delay of 1 sec but -- output is printed every second because both stages are concurrent. -- --
-- >>> import Control.Concurrent (threadDelay) -- -- >>> import Streamly.Prelude ((|$.)) -- -- >>> :{ -- Stream.foldlM' (\_ a -> threadDelay 1000000 >> print a) (return ()) -- |$. Stream.replicateM 3 (threadDelay 1000000 >> return 1) -- :} -- 1 -- 1 -- 1 ---- -- Concurrent -- -- Since: 0.3.0 (Streamly) (|$.) :: (IsStream t, MonadAsync m) => (t m a -> m b) -> t m a -> m b infixr 0 |$. -- | Same as |$. but with arguments reversed. -- --
-- (|&.) = flip (|$.) ---- -- Concurrent -- -- Since: 0.3.0 (Streamly) (|&.) :: (IsStream t, MonadAsync m) => t m a -> (t m a -> m b) -> m b infixl 1 |&. -- | Compare two streams for equality using an equality function. eqBy :: (IsStream t, Monad m) => (a -> b -> Bool) -> t m a -> t m b -> m Bool -- | Compare two streams lexicographically using a comparison function. cmpBy :: (IsStream t, Monad m) => (a -> b -> Ordering) -> t m a -> t m b -> m Ordering -- | Returns True if the first stream is the same as or a prefix of -- the second. A stream is a prefix of itself. -- --
-- >>> Stream.isPrefixOf (Stream.fromList "hello") (Stream.fromList "hello" :: SerialT IO Char) -- True --isPrefixOf :: (Eq a, IsStream t, Monad m) => t m a -> t m a -> m Bool -- | Returns True if all the elements of the first stream occur, in -- order, in the second stream. The elements do not have to occur -- consecutively. A stream is a subsequence of itself. -- --
-- >>> Stream.isSubsequenceOf (Stream.fromList "hlo") (Stream.fromList "hello" :: SerialT IO Char) -- True --isSubsequenceOf :: (Eq a, IsStream t, Monad m) => t m a -> t m a -> m Bool -- | stripPrefix prefix stream strips prefix from -- stream if it is a prefix of stream. Returns Nothing if -- the stream does not start with the given prefix, stripped stream -- otherwise. Returns Just nil when the prefix is the same as -- the stream. -- -- See also "Streamly.Internal.Data.Stream.IsStream.Nesting.dropPrefix". -- -- Space: O(1) stripPrefix :: (Eq a, IsStream t, Monad m) => t m a -> t m a -> m (Maybe (t m a)) -- |
-- map = fmap ---- -- Same as fmap. -- --
-- > D.toList $ D.map (+1) $ D.fromList [1,2,3] -- [2,3,4] --map :: (IsStream t, Monad m) => (a -> b) -> t m a -> t m b -- |
-- sequence = mapM id ---- -- Replace the elements of a stream of monadic actions with the outputs -- of those actions. -- --
-- >>> drain $ Stream.sequence $ Stream.fromList [putStr "a", putStr "b", putStrLn "c"] -- abc -- -- >>> :{ -- drain $ Stream.replicateM 3 (return $ threadDelay 1000000 >> print 1) -- & (fromSerial . Stream.sequence) -- :} -- 1 -- 1 -- 1 -- -- >>> :{ -- drain $ Stream.replicateM 3 (return $ threadDelay 1000000 >> print 1) -- & (fromAsync . Stream.sequence) -- :} -- 1 -- 1 -- 1 ---- -- Concurrent (do not use with fromParallel on infinite -- streams) sequence :: (IsStream t, MonadAsync m) => t m (m a) -> t m a -- |
-- mapM f = sequence . map f ---- -- Apply a monadic function to each element of the stream and replace it -- with the output of the resulting action. -- --
-- >>> drain $ Stream.mapM putStr $ Stream.fromList ["a", "b", "c"] -- abc -- -- >>> :{ -- drain $ Stream.replicateM 10 (return 1) -- & (fromSerial . Stream.mapM (x -> threadDelay 1000000 >> print x)) -- :} -- 1 -- ... -- 1 -- -- > drain $ Stream.replicateM 10 (return 1) -- & (fromAsync . Stream.mapM (x -> threadDelay 1000000 >> print x)) ---- -- Concurrent (do not use with fromParallel on infinite -- streams) mapM :: forall t m a b. (IsStream t, MonadAsync m) => (a -> m b) -> t m a -> t m b -- |
-- mapM_ = Stream.drain . Stream.mapM ---- -- Apply a monadic action to each element of the stream and discard the -- output of the action. This is not really a pure transformation -- operation but a transformation followed by fold. mapM_ :: Monad m => (a -> m b) -> SerialT m a -> m () -- | Apply a monadic function to each element flowing through the stream -- and discard the results. -- --
-- >>> Stream.drain $ Stream.trace print (Stream.enumerateFromTo 1 2) -- 1 -- 2 ---- -- Compare with tap. trace :: (IsStream t, MonadAsync m) => (a -> m b) -> t m a -> t m a -- | Tap the data flowing through a stream into a Fold. For example, -- you may add a tap to log the contents flowing through the stream. The -- fold is used only for effects, its result is discarded. -- --
-- Fold m a b -- | -- -----stream m a ---------------stream m a----- ---- --
-- >>> Stream.drain $ Stream.tap (Fold.drainBy print) (Stream.enumerateFromTo 1 2) -- 1 -- 2 ---- -- Compare with trace. tap :: (IsStream t, Monad m) => Fold m a b -> t m a -> t m a -- | Introduce a delay of specified seconds before consuming an element of -- the stream except the first one. -- --
-- >>> Stream.mapM_ print $ Stream.timestamped $ Stream.delay 1 $ Stream.enumerateFromTo 1 3 -- (AbsTime (TimeSpec {sec = ..., nsec = ...}),1) -- (AbsTime (TimeSpec {sec = ..., nsec = ...}),2) -- (AbsTime (TimeSpec {sec = ..., nsec = ...}),3) --delay :: (IsStream t, MonadIO m) => Double -> t m a -> t m a -- | Strict left scan. Like map, scanl' too is a one to one -- transformation, however it adds an extra element. -- --
-- >>> Stream.toList $ Stream.scanl' (+) 0 $ fromList [1,2,3,4] -- [0,1,3,6,10] ---- --
-- >>> Stream.toList $ Stream.scanl' (flip (:)) [] $ Stream.fromList [1,2,3,4] -- [[],[1],[2,1],[3,2,1],[4,3,2,1]] ---- -- The output of scanl' is the initial value of the accumulator -- followed by all the intermediate steps and the final result of -- foldl'. -- -- By streaming the accumulated state after each fold step, we can share -- the state across multiple stages of stream composition. Each stage can -- modify or extend the state, do some processing with it and emit it for -- the next stage, thus modularizing the stream processing. This can be -- useful in stateful or event-driven programming. -- -- Consider the following monolithic example, computing the sum and the -- product of the elements in a stream in one go using a foldl': -- --
-- >>> Stream.foldl' ((s, p) x -> (s + x, p * x)) (0,1) $ Stream.fromList 1,2,3,4 ---- -- Using scanl' we can make it modular by computing the sum in -- the first stage and passing it down to the next stage for computing -- the product: -- --
-- >>> :{ -- Stream.foldl' ((_, p) (s, x) -> (s, p * x)) (0,1) -- $ Stream.scanl' ((s, _) x -> (s + x, x)) (0,1) -- $ Stream.fromList [1,2,3,4] -- :} -- (10,24) ---- -- IMPORTANT: scanl' evaluates the accumulator to WHNF. To avoid -- building lazy expressions inside the accumulator, it is recommended -- that a strict data structure is used for accumulator. -- --
-- >>> scanl' step z = scan (Fold.foldl' step z) -- -- >>> scanl' f z xs = scanlM' (\a b -> return (f a b)) (return z) xs -- -- >>> scanl' f z xs = z `Stream.cons` postscanl' f z xs ---- -- See also: usingStateT scanl' :: (IsStream t, Monad m) => (b -> a -> b) -> b -> t m a -> t m b -- | Like scanl' but with a monadic step function and a monadic -- seed. -- -- Since: 0.4.0 -- -- Since: 0.8.0 (signature change) scanlM' :: (IsStream t, Monad m) => (b -> a -> m b) -> m b -> t m a -> t m b -- | Like scanl' but does not stream the initial value of the -- accumulator. -- --
-- >>> postscanl' step z = postscan (Fold.foldl' step z) -- -- >>> postscanl' f z = postscanlM' (\a b -> return (f a b)) (return z) -- -- >>> postscanl' f z xs = Stream.drop 1 $ Stream.scanl' f z xs --postscanl' :: (IsStream t, Monad m) => (b -> a -> b) -> b -> t m a -> t m b -- | Like postscanl' but with a monadic step function and a -- monadic seed. -- --
-- >>> postscanlM' f z xs = Stream.drop 1 $ Stream.scanlM' f z xs ---- -- Since: 0.7.0 -- -- Since: 0.8.0 (signature change) postscanlM' :: (IsStream t, Monad m) => (b -> a -> m b) -> m b -> t m a -> t m b -- | Like scanl' but for a non-empty stream. The first element of -- the stream is used as the initial value of the accumulator. Does -- nothing if the stream is empty. -- --
-- >>> Stream.toList $ Stream.scanl1' (+) $ fromList [1,2,3,4] -- [1,3,6,10] --scanl1' :: (IsStream t, Monad m) => (a -> a -> a) -> t m a -> t m a -- | Like scanl1' but with a monadic step function. scanl1M' :: (IsStream t, Monad m) => (a -> a -> m a) -> t m a -> t m a -- | Scan a stream using the given monadic fold. -- --
-- >>> Stream.toList $ Stream.takeWhile (< 10) $ Stream.scan Fold.sum (Stream.fromList [1..10]) -- [0,1,3,6] --scan :: (IsStream t, Monad m) => Fold m a b -> t m a -> t m b -- | Postscan a stream using the given monadic fold. -- -- The following example extracts the input stream up to a point where -- the running average of elements is no more than 10: -- --
-- >>> import Data.Maybe (fromJust) -- -- >>> let avg = Fold.teeWith (/) Fold.sum (fmap fromIntegral Fold.length) -- -- >>> :{ -- Stream.toList -- $ Stream.map (fromJust . fst) -- $ Stream.takeWhile (\(_,x) -> x <= 10) -- $ Stream.postscan (Fold.tee Fold.last avg) (Stream.enumerateFromTo 1.0 100.0) -- :} -- [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0,16.0,17.0,18.0,19.0] --postscan :: (IsStream t, Monad m) => Fold m a b -> t m a -> t m b -- | Deletes the first occurrence of the element in the stream that -- satisfies the given equality predicate. -- --
-- >>> Stream.toList $ Stream.deleteBy (==) 3 $ Stream.fromList [1,3,3,5] -- [1,3,5] --deleteBy :: (IsStream t, Monad m) => (a -> a -> Bool) -> a -> t m a -> t m a -- | Include only those elements that pass a predicate. filter :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> t m a -- | Same as filter but with a monadic predicate. filterM :: (IsStream t, Monad m) => (a -> m Bool) -> t m a -> t m a -- | Drop repeated elements that are adjacent to each other. uniq :: (Eq a, IsStream t, Monad m) => t m a -> t m a -- | Take first n elements from the stream and discard the rest. take :: (IsStream t, Monad m) => Int -> t m a -> t m a -- | End the stream as soon as the predicate fails on an element. takeWhile :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> t m a -- | Same as takeWhile but with a monadic predicate. takeWhileM :: (IsStream t, Monad m) => (a -> m Bool) -> t m a -> t m a -- | Discard first n elements from the stream and take the rest. drop :: (IsStream t, Monad m) => Int -> t m a -> t m a -- | Drop elements in the stream as long as the predicate succeeds and then -- take the rest of the stream. dropWhile :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> t m a -- | Same as dropWhile but with a monadic predicate. dropWhileM :: (IsStream t, Monad m) => (a -> m Bool) -> t m a -> t m a -- | insertBy cmp elem stream inserts elem before the -- first element in stream that is less than elem when -- compared using cmp. -- --
-- insertBy cmp x = mergeBy cmp (fromPure x) ---- --
-- >>> Stream.toList $ Stream.insertBy compare 2 $ Stream.fromList [1,3,5] -- [1,2,3,5] --insertBy :: (IsStream t, Monad m) => (a -> a -> Ordering) -> a -> t m a -> t m a -- | Insert an effect and its output before consuming an element of a -- stream except the first one. -- --
-- >>> Stream.toList $ Stream.trace putChar $ Stream.intersperseM (putChar '.' >> return ',') $ Stream.fromList "hello" -- h.,e.,l.,l.,o"h,e,l,l,o" ---- -- Be careful about the order of effects. In the above example we used -- trace after the intersperse, if we use it before the intersperse the -- output would be he.l.l.o."h,e,l,l,o". -- --
-- >>> Stream.toList $ Stream.intersperseM (putChar '.' >> return ',') $ Stream.trace putChar $ Stream.fromList "hello" -- he.l.l.o."h,e,l,l,o" --intersperseM :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a -- | Insert a pure value between successive elements of a stream. -- --
-- >>> Stream.toList $ Stream.intersperse ',' $ Stream.fromList "hello" -- "h,e,l,l,o" --intersperse :: (IsStream t, MonadAsync m) => a -> t m a -> t m a -- | Returns the elements of the stream in reverse order. The stream must -- be finite. Note that this necessarily buffers the entire stream in -- memory. -- --
-- >>> reverse = Stream.foldlT (flip Stream.cons) Stream.nil ---- -- Since 0.7.0 (Monad m constraint) -- -- Since: 0.1.1 reverse :: (IsStream t, Monad m) => t m a -> t m a -- |
-- indexed = Stream.postscanl' (\(i, _) x -> (i + 1, x)) (-1,undefined) -- indexed = Stream.zipWith (,) (Stream.enumerateFrom 0) ---- -- Pair each element in a stream with its index, starting from index 0. -- --
-- >>> Stream.toList $ Stream.indexed $ Stream.fromList "hello" -- [(0,'h'),(1,'e'),(2,'l'),(3,'l'),(4,'o')] --indexed :: (IsStream t, Monad m) => t m a -> t m (Int, a) -- |
-- indexedR n = Stream.postscanl' (\(i, _) x -> (i - 1, x)) (n + 1,undefined) -- indexedR n = Stream.zipWith (,) (Stream.enumerateFromThen n (n - 1)) ---- -- Pair each element in a stream with its index, starting from the given -- index n and counting down. -- --
-- >>> Stream.toList $ Stream.indexedR 10 $ Stream.fromList "hello" -- [(10,'h'),(9,'e'),(8,'l'),(7,'l'),(6,'o')] --indexedR :: (IsStream t, Monad m) => Int -> t m a -> t m (Int, a) -- | Find all the indices where the element in the stream satisfies the -- given predicate. -- --
-- findIndices = fold Fold.findIndices --findIndices :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> t m Int -- | Find all the indices where the value of the element in the stream is -- equal to the given value. -- --
-- elemIndices a = findIndices (== a) --elemIndices :: (IsStream t, Eq a, Monad m) => a -> t m a -> t m Int -- | Map a Maybe returning function to a stream, filter out the -- Nothing elements, and return a stream of values extracted from -- Just. -- -- Equivalent to: -- --
-- mapMaybe f = Stream.map fromJust . Stream.filter isJust . Stream.map f --mapMaybe :: (IsStream t, Monad m) => (a -> Maybe b) -> t m a -> t m b -- | Like mapMaybe but maps a monadic function. -- -- Equivalent to: -- --
-- mapMaybeM f = Stream.map fromJust . Stream.filter isJust . Stream.mapM f ---- -- Concurrent (do not use with fromParallel on infinite -- streams) mapMaybeM :: (IsStream t, MonadAsync m, Functor (t m)) => (a -> m (Maybe b)) -> t m a -> t m b -- | Parallel transform application operator; applies a stream -- transformation function t m a -> t m b to a stream t m -- a concurrently; the input stream is evaluated asynchronously in -- an independent thread yielding elements to a buffer and the -- transformation function runs in another thread consuming the input -- from the buffer. |$ is just like regular function application -- operator $ except that it is concurrent. -- -- If you read the signature as (t m a -> t m b) -> (t m a -- -> t m b) you can look at it as a transformation that converts -- a transform function to a buffered concurrent transform function. -- -- The following code prints a value every second even though each stage -- adds a 1 second delay. -- --
-- >>> :{ -- Stream.drain $ -- Stream.mapM (\x -> threadDelay 1000000 >> print x) -- |$ Stream.replicateM 3 (threadDelay 1000000 >> return 1) -- :} -- 1 -- 1 -- 1 ---- -- Concurrent -- -- Since: 0.3.0 (Streamly) (|$) :: (IsStream t, MonadAsync m) => (t m a -> t m b) -> t m a -> t m b infixr 0 |$ -- | Same as |$ but with arguments reversed. -- -- (|&) = flip (|$) -- -- Concurrent -- -- Since: 0.3.0 (Streamly) (|&) :: (IsStream t, MonadAsync m) => t m a -> (t m a -> t m b) -> t m b infixl 1 |& -- | Make the stream producer and consumer run concurrently by introducing -- a buffer between them. The producer thread evaluates the input stream -- until the buffer fills, it terminates if the buffer is full and a -- worker thread is kicked off again to evaluate the remaining stream -- when there is space in the buffer. The consumer consumes the stream -- lazily from the buffer. -- -- Since: 0.2.0 (Streamly) mkAsync :: (IsStream t, MonadAsync m) => t m a -> t m a -- | Specify the maximum number of threads that can be spawned concurrently -- for any concurrent combinator in a stream. A value of 0 resets the -- thread limit to default, a negative value means there is no limit. The -- default value is 1500. maxThreads does not affect -- ParallelT streams as they can use unbounded number of -- threads. -- -- When the actions in a stream are IO bound, having blocking IO calls, -- this option can be used to control the maximum number of in-flight IO -- requests. When the actions are CPU bound this option can be used to -- control the amount of CPU used by the stream. -- -- Since: 0.4.0 (Streamly) maxThreads :: IsStream t => Int -> t m a -> t m a -- | Specify the maximum size of the buffer for storing the results from -- concurrent computations. If the buffer becomes full we stop spawning -- more concurrent tasks until there is space in the buffer. A value of 0 -- resets the buffer size to default, a negative value means there is no -- limit. The default value is 1500. -- -- CAUTION! using an unbounded maxBuffer value (i.e. a negative -- value) coupled with an unbounded maxThreads value is a recipe -- for disaster in presence of infinite streams, or very large streams. -- Especially, it must not be used when pure is used in -- ZipAsyncM streams as pure in applicative zip streams -- generates an infinite stream causing unbounded concurrent generation -- with no limit on the buffer or threads. -- -- Since: 0.4.0 (Streamly) maxBuffer :: IsStream t => Int -> t m a -> t m a data Rate Rate :: Double -> Double -> Double -> Int -> Rate [rateLow] :: Rate -> Double [rateGoal] :: Rate -> Double [rateHigh] :: Rate -> Double [rateBuffer] :: Rate -> Int -- | Specify the pull rate of a stream. A Nothing value resets the -- rate to default which is unlimited. When the rate is specified, -- concurrent production may be ramped up or down automatically to -- achieve the specified yield rate. The specific behavior for different -- styles of Rate specifications is documented under Rate. -- The effective maximum production rate achieved by a stream is governed -- by: -- --
-- >>> import Streamly.Prelude (serial) -- -- >>> stream1 = Stream.fromList [1,2] -- -- >>> stream2 = Stream.fromList [3,4] -- -- >>> Stream.toList $ stream1 `serial` stream2 -- [1,2,3,4] ---- -- This operation can be used to fold an infinite lazy container of -- streams. -- -- Since: 0.2.0 (Streamly) serial :: IsStream t => t m a -> t m a -> t m a infixr 6 `serial` -- | Interleaves two streams, yielding one element from each stream -- alternately. When one stream stops the rest of the other stream is -- used in the output stream. -- --
-- >>> import Streamly.Prelude (wSerial) -- -- >>> stream1 = Stream.fromList [1,2] -- -- >>> stream2 = Stream.fromList [3,4] -- -- >>> Stream.toList $ Stream.fromWSerial $ stream1 `wSerial` stream2 -- [1,3,2,4] ---- -- Note, for singleton streams wSerial and serial are -- identical. -- -- Note that this operation cannot be used to fold a container of -- infinite streams but it can be used for very large streams as the -- state that it needs to maintain is proportional to the logarithm of -- the number of streams. -- -- Since: 0.2.0 (Streamly) wSerial :: IsStream t => t m a -> t m a -> t m a infixr 6 `wSerial` -- | Appends two streams, both the streams may be evaluated concurrently -- but the outputs are used in the same order as the corresponding -- actions in the original streams, side effects will happen in the order -- in which the streams are evaluated: -- --
-- >>> import Streamly.Prelude (ahead, SerialT) -- -- >>> stream1 = Stream.fromEffect (delay 4) :: SerialT IO Int -- -- >>> stream2 = Stream.fromEffect (delay 2) :: SerialT IO Int -- -- >>> Stream.toList $ stream1 `ahead` stream2 :: IO [Int] -- 2 sec -- 4 sec -- [4,2] ---- -- Multiple streams can be combined. With enough threads, all of them can -- be scheduled simultaneously: -- --
-- >>> stream3 = Stream.fromEffect (delay 1) -- -- >>> Stream.toList $ stream1 `ahead` stream2 `ahead` stream3 -- 1 sec -- 2 sec -- 4 sec -- [4,2,1] ---- -- With 2 threads, only two can be scheduled at a time, when one of those -- finishes, the third one gets scheduled: -- --
-- >>> Stream.toList $ Stream.maxThreads 2 $ stream1 `ahead` stream2 `ahead` stream3 -- 2 sec -- 1 sec -- 4 sec -- [4,2,1] ---- -- Only streams are scheduled for ahead evaluation, how actions within a -- stream are evaluated depends on the stream type. If it is a concurrent -- stream they will be evaluated concurrently. It may not make much sense -- combining serial streams using ahead. -- -- ahead can be safely used to fold an infinite lazy container of -- streams. -- -- Since: 0.3.0 (Streamly) ahead :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a infixr 6 `ahead` -- | Merges two streams, both the streams may be evaluated concurrently, -- outputs from both are used as they arrive: -- --
-- >>> import Streamly.Prelude (async) -- -- >>> stream1 = Stream.fromEffect (delay 4) -- -- >>> stream2 = Stream.fromEffect (delay 2) -- -- >>> Stream.toList $ stream1 `async` stream2 -- 2 sec -- 4 sec -- [2,4] ---- -- Multiple streams can be combined. With enough threads, all of them can -- be scheduled simultaneously: -- --
-- >>> stream3 = Stream.fromEffect (delay 1) -- -- >>> Stream.toList $ stream1 `async` stream2 `async` stream3 -- ... -- [1,2,4] ---- -- With 2 threads, only two can be scheduled at a time, when one of those -- finishes, the third one gets scheduled: -- --
-- >>> Stream.toList $ Stream.maxThreads 2 $ stream1 `async` stream2 `async` stream3 -- ... -- [2,1,4] ---- -- With a single thread, it becomes serial: -- --
-- >>> Stream.toList $ Stream.maxThreads 1 $ stream1 `async` stream2 `async` stream3 -- ... -- [4,2,1] ---- -- Only streams are scheduled for async evaluation, how actions within a -- stream are evaluated depends on the stream type. If it is a concurrent -- stream they will be evaluated concurrently. -- -- In the following example, both the streams are scheduled for -- concurrent evaluation but each individual stream is evaluated -- serially: -- --
-- >>> stream1 = Stream.fromListM $ Prelude.map delay [3,3] -- SerialT IO Int -- -- >>> stream2 = Stream.fromListM $ Prelude.map delay [1,1] -- SerialT IO Int -- -- >>> Stream.toList $ stream1 `async` stream2 -- IO [Int] -- ... -- [1,1,3,3] ---- -- If total threads are 2, the third stream is scheduled only after one -- of the first two has finished: -- --
-- stream3 = Stream.fromListM $ Prelude.map delay [2,2] -- SerialT IO Int -- Stream.toList $ Stream.maxThreads 2 $ stream1 `async` stream2 `async` stream3 -- IO [Int] ---- -- ... [1,1,3,2,3,2] -- -- Thus async goes deep in first few streams rather than going -- wide in all streams. It prefers to evaluate the leftmost streams as -- much as possible. Because of this behavior, async can be safely -- used to fold an infinite lazy container of streams. -- -- Since: 0.2.0 (Streamly) async :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a infixr 6 `async` -- | For singleton streams, wAsync is the same as async. See -- async for singleton stream behavior. For multi-element streams, -- while async is left biased i.e. it tries to evaluate the left -- side stream as much as possible, wAsync tries to schedule them -- both fairly. In other words, async goes deep while -- wAsync goes wide. However, outputs are always used as they -- arrive. -- -- With a single thread, async starts behaving like serial -- while wAsync starts behaving like wSerial. -- --
-- >>> import Streamly.Prelude (async, wAsync) -- -- >>> stream1 = Stream.fromList [1,2,3] -- -- >>> stream2 = Stream.fromList [4,5,6] -- -- >>> Stream.toList $ Stream.fromAsync $ Stream.maxThreads 1 $ stream1 `async` stream2 -- [1,2,3,4,5,6] ---- --
-- >>> Stream.toList $ Stream.fromWAsync $ Stream.maxThreads 1 $ stream1 `wAsync` stream2 -- [1,4,2,5,3,6] ---- -- With two threads available, and combining three streams: -- --
-- >>> stream3 = Stream.fromList [7,8,9] -- -- >>> Stream.toList $ Stream.fromAsync $ Stream.maxThreads 2 $ stream1 `async` stream2 `async` stream3 -- [1,2,3,4,5,6,7,8,9] ---- --
-- >>> Stream.toList $ Stream.fromWAsync $ Stream.maxThreads 2 $ stream1 `wAsync` stream2 `wAsync` stream3 -- [1,4,2,7,5,3,8,6,9] ---- -- This operation cannot be used to fold an infinite lazy container of -- streams, because it schedules all the streams in a round robin manner. -- -- Note that WSerialT and single threaded WAsyncT both -- interleave streams but the exact scheduling is slightly different in -- both cases. -- -- Since: 0.2.0 (Streamly) wAsync :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a infixr 6 `wAsync` -- | Like async except that the execution is much more strict. There -- is no limit on the number of threads. While async may not -- schedule a stream if there is no demand from the consumer, -- parallel always evaluates both the streams immediately. The -- only limit that applies to parallel is maxBuffer. -- Evaluation may block if the output buffer becomes full. -- --
-- >>> import Streamly.Prelude (parallel) -- -- >>> stream = Stream.fromEffect (delay 2) `parallel` Stream.fromEffect (delay 1) -- -- >>> Stream.toList stream -- IO [Int] -- 1 sec -- 2 sec -- [1,2] ---- -- parallel guarantees that all the streams are scheduled for -- execution immediately, therefore, we could use things like starting -- timers inside the streams and relying on the fact that all timers were -- started at the same time. -- -- Unlike async this operation cannot be used to fold an infinite -- lazy container of streams, because it schedules all the streams -- strictly concurrently. -- -- Since: 0.2.0 (Streamly) parallel :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a infixr 6 `parallel` -- | Merge two streams using a comparison function. The head elements of -- both the streams are compared and the smaller of the two elements is -- emitted, if both elements are equal then the element from the first -- stream is used first. -- -- If the streams are sorted in ascending order, the resulting stream -- would also remain sorted in ascending order. -- --
-- >>> Stream.toList $ Stream.mergeBy compare (Stream.fromList [1,3,5]) (Stream.fromList [2,4,6,8]) -- [1,2,3,4,5,6,8] ---- -- See also: mergeByMFused mergeBy :: IsStream t => (a -> a -> Ordering) -> t m a -> t m a -> t m a -- | Like mergeBy but with a monadic comparison function. -- -- Merge two streams randomly: -- --
-- > randomly _ _ = randomIO >>= x -> return $ if x then LT else GT -- > Stream.toList $ Stream.mergeByM randomly (Stream.fromList [1,1,1,1]) (Stream.fromList [2,2,2,2]) -- [2,1,2,2,2,1,1,1] ---- -- Merge two streams in a proportion of 2:1: -- --
-- >>> :{ -- do -- let proportionately m n = do -- ref <- newIORef $ cycle $ Prelude.concat [Prelude.replicate m LT, Prelude.replicate n GT] -- return $ _ _ -> do -- r <- readIORef ref -- writeIORef ref $ Prelude.tail r -- return $ Prelude.head r -- f <- proportionately 2 1 -- xs <- Stream.toList $ Stream.mergeByM f (Stream.fromList [1,1,1,1,1,1]) (Stream.fromList [2,2,2]) -- print xs -- :} -- [1,1,2,1,1,2,1,1,2] ---- -- See also: mergeByMFused mergeByM :: (IsStream t, Monad m) => (a -> a -> m Ordering) -> t m a -> t m a -> t m a -- | Like mergeBy but merges concurrently (i.e. both the elements -- being merged are generated concurrently). mergeAsyncBy :: (IsStream t, MonadAsync m) => (a -> a -> Ordering) -> t m a -> t m a -> t m a -- | Like mergeByM but merges concurrently (i.e. both the elements -- being merged are generated concurrently). mergeAsyncByM :: (IsStream t, MonadAsync m) => (a -> a -> m Ordering) -> t m a -> t m a -> t m a -- | Stream a is evaluated first, followed by stream b, -- the resulting elements a and b are then zipped using -- the supplied zip function and the result c is yielded to the -- consumer. -- -- If stream a or stream b ends, the zipped stream -- ends. If stream b ends first, the element a from -- previous evaluation of stream a is discarded. -- --
-- > D.toList $ D.zipWith (+) (D.fromList [1,2,3]) (D.fromList [4,5,6]) -- [5,7,9] --zipWith :: (IsStream t, Monad m) => (a -> b -> c) -> t m a -> t m b -> t m c -- | Like zipWith but using a monadic zipping function. zipWithM :: (IsStream t, Monad m) => (a -> b -> m c) -> t m a -> t m b -> t m c -- | Like zipWith but zips concurrently i.e. both the streams being -- zipped are evaluated concurrently using the ParallelT -- concurrent evaluation style. The maximum number of elements of each -- stream evaluated in advance can be controlled by maxBuffer. -- -- The stream ends if stream a or stream b ends. -- However, if stream b ends while we are still evaluating -- stream a and waiting for a result then stream will not end -- until after the evaluation of stream a finishes. This -- behavior can potentially be changed in future to end the stream -- immediately as soon as any of the stream end is detected. zipAsyncWith :: (IsStream t, MonadAsync m) => (a -> b -> c) -> t m a -> t m b -> t m c -- | Like zipAsyncWith but with a monadic zipping function. zipAsyncWithM :: (IsStream t, MonadAsync m) => (a -> b -> m c) -> t m a -> t m b -> t m c -- | Like concatMap but uses an Unfold for stream generation. -- Unlike concatMap this can fuse the Unfold code with the -- inner loop and therefore provide many times better performance. unfoldMany :: (IsStream t, Monad m) => Unfold m a b -> t m a -> t m b -- | intersperse followed by unfold and concat. -- --
-- intercalate unf a str = unfoldMany unf $ intersperse a str -- intersperse = intercalate (Unfold.function id) -- unwords = intercalate Unfold.fromList " " ---- --
-- >>> Stream.toList $ Stream.intercalate Unfold.fromList " " $ Stream.fromList ["abc", "def", "ghi"] -- "abc def ghi" --intercalate :: (IsStream t, Monad m) => Unfold m b c -> b -> t m b -> t m c -- | intersperseMSuffix followed by unfold and concat. -- --
-- intercalateSuffix unf a str = unfoldMany unf $ intersperseMSuffix a str -- intersperseMSuffix = intercalateSuffix (Unfold.function id) -- unlines = intercalateSuffix Unfold.fromList "\n" ---- --
-- >>> Stream.toList $ Stream.intercalateSuffix Unfold.fromList "\n" $ Stream.fromList ["abc", "def", "ghi"] -- "abc\ndef\nghi\n" --intercalateSuffix :: (IsStream t, Monad m) => Unfold m b c -> b -> t m b -> t m c -- | concatMapWith mixer generator stream is a two dimensional -- looping combinator. The generator function is used to -- generate streams from the elements in the input stream and -- the mixer function is used to merge those streams. -- -- Note we can merge streams concurrently by using a concurrent merge -- function. -- -- Since: 0.7.0 -- -- Since: 0.8.0 (signature change) concatMapWith :: IsStream t => (t m b -> t m b -> t m b) -> (a -> t m b) -> t m a -> t m b -- | Map a stream producing function on each element of the stream and then -- flatten the results into a single stream. -- --
-- >>> concatMap f = Stream.concatMapM (return . f) -- -- >>> concatMap f = Stream.concatMapWith Stream.serial f -- -- >>> concatMap f = Stream.concat . Stream.map f --concatMap :: (IsStream t, Monad m) => (a -> t m b) -> t m a -> t m b -- | Map a stream producing monadic function on each element of the stream -- and then flatten the results into a single stream. Since the stream -- generation function is monadic, unlike concatMap, it can -- produce an effect at the beginning of each iteration of the inner -- loop. concatMapM :: (IsStream t, Monad m) => (a -> m (t m b)) -> t m a -> t m b -- | A variant of fold that allows you to fold a Foldable -- container of streams using the specified stream sum operation. -- --
-- concatFoldableWith async $ map return [1..3] ---- -- Equivalent to: -- --
-- concatFoldableWith f = Prelude.foldr f D.nil -- concatFoldableWith f = D.concatMapFoldableWith f id ---- -- Since: 0.8.0 (Renamed foldWith to concatFoldableWith) -- -- Since: 0.1.0 (Streamly) concatFoldableWith :: (IsStream t, Foldable f) => (t m a -> t m a -> t m a) -> f (t m a) -> t m a -- | A variant of foldMap that allows you to map a monadic -- streaming action on a Foldable container and then fold it using -- the specified stream merge operation. -- --
-- concatMapFoldableWith async return [1..3] ---- -- Equivalent to: -- --
-- concatMapFoldableWith f g = Prelude.foldr (f . g) S.nil -- concatMapFoldableWith f g xs = S.concatMapWith f g (S.fromFoldable xs) ---- -- Since: 0.8.0 (Renamed foldMapWith to concatMapFoldableWith) -- -- Since: 0.1.0 (Streamly) concatMapFoldableWith :: (IsStream t, Foldable f) => (t m b -> t m b -> t m b) -> (a -> t m b) -> f a -> t m b -- | Like concatMapFoldableWith but with the last two arguments -- reversed i.e. the monadic streaming function is the last argument. -- -- Equivalent to: -- --
-- concatForFoldableWith f xs g = Prelude.foldr (f . g) D.nil xs -- concatForFoldableWith f = flip (D.concatMapFoldableWith f) ---- -- Since: 0.8.0 (Renamed forEachWith to concatForFoldableWith) -- -- Since: 0.1.0 (Streamly) concatForFoldableWith :: (IsStream t, Foldable f) => (t m b -> t m b -> t m b) -> f a -> (a -> t m b) -> t m b -- | Apply a Fold repeatedly on a stream and emit the fold outputs -- in the output stream. -- -- To sum every two contiguous elements in a stream: -- --
-- >>> f = Fold.take 2 Fold.sum -- -- >>> Stream.toList $ Stream.foldMany f $ Stream.fromList [1..10] -- [3,7,11,15,19] ---- -- On an empty stream the output is empty: -- --
-- >>> Stream.toList $ Stream.foldMany f $ Stream.fromList [] -- [] ---- -- Note Stream.foldMany (Fold.take 0) would result in an -- infinite loop in a non-empty stream. foldMany :: (IsStream t, Monad m) => Fold m a b -> t m a -> t m b -- | Group the input stream into groups of n elements each and -- then fold each group using the provided fold function. -- --
-- >>> Stream.toList $ Stream.chunksOf 2 Fold.sum (Stream.enumerateFromTo 1 10) -- [3,7,11,15,19] ---- -- This can be considered as an n-fold version of take where we -- apply take repeatedly on the leftover stream until the stream -- exhausts. -- --
-- chunksOf n f = foldMany (FL.take n f) --chunksOf :: (IsStream t, Monad m) => Int -> Fold m a b -> t m a -> t m b -- | Group the input stream into windows of n second each and then -- fold each group using the provided fold function. -- --
-- >>> Stream.toList $ Stream.take 5 $ Stream.intervalsOf 1 Fold.sum $ Stream.constRate 2 $ Stream.enumerateFrom 1 -- [...,...,...,...,...] --intervalsOf :: (IsStream t, MonadAsync m) => Double -> Fold m a b -> t m a -> t m b -- | Split on an infixed separator element, dropping the separator. The -- supplied Fold is applied on the split segments. Splits the -- stream on separator elements determined by the supplied predicate, -- separator is considered as infixed between two segments: -- --
-- >>> splitOn' p xs = Stream.toList $ Stream.splitOn p Fold.toList (Stream.fromList xs) -- -- >>> splitOn' (== '.') "a.b" -- ["a","b"] ---- -- An empty stream is folded to the default value of the fold: -- --
-- >>> splitOn' (== '.') "" -- [""] ---- -- If one or both sides of the separator are missing then the empty -- segment on that side is folded to the default output of the fold: -- --
-- >>> splitOn' (== '.') "." -- ["",""] ---- --
-- >>> splitOn' (== '.') ".a" -- ["","a"] ---- --
-- >>> splitOn' (== '.') "a." -- ["a",""] ---- --
-- >>> splitOn' (== '.') "a..b" -- ["a","","b"] ---- -- splitOn is an inverse of intercalating single element: -- --
-- Stream.intercalate (Stream.fromPure '.') Unfold.fromList . Stream.splitOn (== '.') Fold.toList === id ---- -- Assuming the input stream does not contain the separator: -- --
-- Stream.splitOn (== '.') Fold.toList . Stream.intercalate (Stream.fromPure '.') Unfold.fromList === id --splitOn :: (IsStream t, Monad m) => (a -> Bool) -> Fold m a b -> t m a -> t m b -- | Split on a suffixed separator element, dropping the separator. The -- supplied Fold is applied on the split segments. -- --
-- >>> splitOnSuffix' p xs = Stream.toList $ Stream.splitOnSuffix p Fold.toList (Stream.fromList xs) -- -- >>> splitOnSuffix' (== '.') "a.b." -- ["a","b"] ---- --
-- >>> splitOnSuffix' (== '.') "a." -- ["a"] ---- -- An empty stream results in an empty output stream: -- --
-- >>> splitOnSuffix' (== '.') "" -- [] ---- -- An empty segment consisting of only a suffix is folded to the default -- output of the fold: -- --
-- >>> splitOnSuffix' (== '.') "." -- [""] ---- --
-- >>> splitOnSuffix' (== '.') "a..b.." -- ["a","","b",""] ---- -- A suffix is optional at the end of the stream: -- --
-- >>> splitOnSuffix' (== '.') "a" -- ["a"] ---- --
-- >>> splitOnSuffix' (== '.') ".a" -- ["","a"] ---- --
-- >>> splitOnSuffix' (== '.') "a.b" -- ["a","b"] ---- --
-- lines = splitOnSuffix (== '\n') ---- -- splitOnSuffix is an inverse of intercalateSuffix with -- a single element: -- --
-- Stream.intercalateSuffix (Stream.fromPure '.') Unfold.fromList . Stream.splitOnSuffix (== '.') Fold.toList === id ---- -- Assuming the input stream does not contain the separator: -- --
-- Stream.splitOnSuffix (== '.') Fold.toList . Stream.intercalateSuffix (Stream.fromPure '.') Unfold.fromList === id --splitOnSuffix :: (IsStream t, Monad m) => (a -> Bool) -> Fold m a b -> t m a -> t m b -- | Like splitOnSuffix but keeps the suffix attached to the -- resulting splits. -- --
-- >>> splitWithSuffix' p xs = Stream.toList $ splitWithSuffix p Fold.toList (Stream.fromList xs) ---- --
-- >>> splitWithSuffix' (== '.') "" -- [] ---- --
-- >>> splitWithSuffix' (== '.') "." -- ["."] ---- --
-- >>> splitWithSuffix' (== '.') "a" -- ["a"] ---- --
-- >>> splitWithSuffix' (== '.') ".a" -- [".","a"] ---- --
-- >>> splitWithSuffix' (== '.') "a." -- ["a."] ---- --
-- >>> splitWithSuffix' (== '.') "a.b" -- ["a.","b"] ---- --
-- >>> splitWithSuffix' (== '.') "a.b." -- ["a.","b."] ---- --
-- >>> splitWithSuffix' (== '.') "a..b.." -- ["a.",".","b.","."] --splitWithSuffix :: (IsStream t, Monad m) => (a -> Bool) -> Fold m a b -> t m a -> t m b -- | Like splitOn after stripping leading, trailing, and repeated -- separators. Therefore, ".a..b." with . as the -- separator would be parsed as ["a","b"]. In other words, its -- like parsing words from whitespace separated text. -- --
-- >>> wordsBy' p xs = Stream.toList $ Stream.wordsBy p Fold.toList (Stream.fromList xs) ---- --
-- >>> wordsBy' (== ',') "" -- [] ---- --
-- >>> wordsBy' (== ',') "," -- [] ---- --
-- >>> wordsBy' (== ',') ",a,,b," -- ["a","b"] ---- --
-- words = wordsBy isSpace --wordsBy :: (IsStream t, Monad m) => (a -> Bool) -> Fold m a b -> t m a -> t m b -- |
-- groups = groupsBy (==) -- groups = groupsByRolling (==) ---- -- Groups contiguous spans of equal elements together in individual -- groups. -- --
-- >>> Stream.toList $ Stream.groups Fold.toList $ Stream.fromList [1,1,2,2] -- [[1,1],[2,2]] --groups :: (IsStream t, Monad m, Eq a) => Fold m a b -> t m a -> t m b -- | groupsBy cmp f $ S.fromList [a,b,c,...] assigns the element -- a to the first group, if b `cmp` a is True -- then b is also assigned to the same group. If c `cmp` -- a is True then c is also assigned to the same -- group and so on. When the comparison fails a new group is started. -- Each group is folded using the fold f and the result of the -- fold is emitted in the output stream. -- --
-- >>> Stream.toList $ Stream.groupsBy (>) Fold.toList $ Stream.fromList [1,3,7,0,2,5] -- [[1,3,7],[0,2,5]] --groupsBy :: (IsStream t, Monad m) => (a -> a -> Bool) -> Fold m a b -> t m a -> t m b -- | Unlike groupsBy this function performs a rolling comparison -- of two successive elements in the input stream. groupsByRolling -- cmp f $ S.fromList [a,b,c,...] assigns the element a to -- the first group, if a `cmp` b is True then b -- is also assigned to the same group. If b `cmp` c is -- True then c is also assigned to the same group and so -- on. When the comparison fails a new group is started. Each group is -- folded using the fold f. -- --
-- >>> Stream.toList $ Stream.groupsByRolling (\a b -> a + 1 == b) Fold.toList $ Stream.fromList [1,2,3,7,8,9] -- [[1,2,3],[7,8,9]] --groupsByRolling :: (IsStream t, Monad m) => (a -> a -> Bool) -> Fold m a b -> t m a -> t m b -- | Run the action m b before the stream yields its first -- element. -- -- Same as the following but more efficient due to fusion: -- --
-- >>> before action xs = Stream.nilM action <> xs -- -- >>> before action xs = Stream.concatMap (const xs) (Stream.fromEffect action) --before :: (IsStream t, Monad m) => m b -> t m a -> t m a -- | Run the action m b whenever the stream t m a stops -- normally, or if it is garbage collected after a partial lazy -- evaluation. -- -- The semantics of the action m b are similar to the semantics -- of cleanup action in bracket. -- -- See also after_ after :: (IsStream t, MonadRunInIO m) => m b -> t m a -> t m a -- | Run the alloc action m b with async exceptions disabled but -- keeping blocking operations interruptible (see mask). Use the -- output b as input to b -> t m a to generate an -- output stream. -- -- b is usually a resource under the state of monad m, -- e.g. a file handle, that requires a cleanup after use. The cleanup -- action b -> m c, runs whenever the stream ends normally, -- due to a sync or async exception or if it gets garbage collected after -- a partial lazy evaluation. -- -- bracket only guarantees that the cleanup action runs, and it -- runs with async exceptions enabled. The action must ensure that it can -- successfully cleanup the resource in the face of sync or async -- exceptions. -- -- When the stream ends normally or on a sync exception, cleanup action -- runs immediately in the current thread context, whereas in other cases -- it runs in the GC context, therefore, cleanup may be delayed until the -- GC gets to run. -- -- See also: bracket_ -- -- Inhibits stream fusion bracket :: (IsStream t, MonadAsync m, MonadCatch m) => m b -> (b -> m c) -> (b -> t m a) -> t m a -- | Run the action m b if the stream aborts due to an exception. -- The exception is not caught, simply rethrown. -- -- Inhibits stream fusion onException :: (IsStream t, MonadCatch m) => m b -> t m a -> t m a -- | Run the action m b whenever the stream t m a stops -- normally, aborts due to an exception or if it is garbage collected -- after a partial lazy evaluation. -- -- The semantics of running the action m b are similar to the -- cleanup action semantics described in bracket. -- -- See also finally_ -- -- Inhibits stream fusion finally :: (IsStream t, MonadAsync m, MonadCatch m) => m b -> t m a -> t m a -- | When evaluating a stream if an exception occurs, stream evaluation -- aborts and the specified exception handler is run with the exception -- as argument. -- -- Inhibits stream fusion handle :: (IsStream t, MonadCatch m, Exception e) => (e -> t m a) -> t m a -> t m a -- | Lift the inner monad m of a stream t m a to tr -- m using the monad transformer tr. liftInner :: (Monad m, IsStream t, MonadTrans tr, Monad (tr m)) => t m a -> t (tr m) a -- | Evaluate the inner monad of a stream as ReaderT. runReaderT :: (IsStream t, Monad m) => m s -> t (ReaderT s m) a -> t m a -- | Evaluate the inner monad of a stream as StateT and emit the -- resulting state and value pair after each step. -- -- This is supported only for SerialT as concurrent state updation -- may not be safe. runStateT :: Monad m => m s -> SerialT (StateT s m) a -> SerialT m (s, a) -- | For SerialT streams: -- --
-- (<>) = serial -- Semigroup -- (>>=) = flip . concatMapWith serial -- Monad ---- -- A single Monad bind behaves like a for loop: -- --
-- >>> :{ -- IsStream.toList $ do -- x <- IsStream.fromList [1,2] -- foreach x in stream -- return x -- :} -- [1,2] ---- -- Nested monad binds behave like nested for loops: -- --
-- >>> :{ -- IsStream.toList $ do -- x <- IsStream.fromList [1,2] -- foreach x in stream -- y <- IsStream.fromList [3,4] -- foreach y in stream -- return (x, y) -- :} -- [(1,3),(1,4),(2,3),(2,4)] ---- -- Since: 0.2.0 (Streamly) data SerialT m a -- | For WSerialT streams: -- --
-- (<>) = wSerial -- Semigroup -- (>>=) = flip . concatMapWith wSerial -- Monad ---- -- Note that <> is associative only if we disregard the -- ordering of elements in the resulting stream. -- -- A single Monad bind behaves like a for loop: -- --
-- >>> :{ -- IsStream.toList $ IsStream.fromWSerial $ do -- x <- IsStream.fromList [1,2] -- foreach x in stream -- return x -- :} -- [1,2] ---- -- Nested monad binds behave like interleaved nested for loops: -- --
-- >>> :{ -- IsStream.toList $ IsStream.fromWSerial $ do -- x <- IsStream.fromList [1,2] -- foreach x in stream -- y <- IsStream.fromList [3,4] -- foreach y in stream -- return (x, y) -- :} -- [(1,3),(2,3),(1,4),(2,4)] ---- -- It is a result of interleaving all the nested iterations corresponding -- to element 1 in the first stream with all the nested -- iterations of element 2: -- --
-- >>> import Streamly.Prelude (wSerial) -- -- >>> IsStream.toList $ IsStream.fromList [(1,3),(1,4)] `IsStream.wSerial` IsStream.fromList [(2,3),(2,4)] -- [(1,3),(2,3),(1,4),(2,4)] ---- -- The W in the name stands for wide or breadth wise -- scheduling in contrast to the depth wise scheduling behavior of -- SerialT. -- -- Since: 0.2.0 (Streamly) data WSerialT m a -- | For AheadT streams: -- --
-- (<>) = ahead -- (>>=) = flip . concatMapWith ahead ---- -- A single Monad bind behaves like a for loop with -- iterations executed concurrently, ahead of time, producing side -- effects of iterations out of order, but results in order: -- --
-- >>> :{ -- Stream.toList $ Stream.fromAhead $ do -- x <- Stream.fromList [2,1] -- foreach x in stream -- Stream.fromEffect $ delay x -- :} -- 1 sec -- 2 sec -- [2,1] ---- -- Nested monad binds behave like nested for loops with nested -- iterations executed concurrently, ahead of time: -- --
-- >>> :{ -- Stream.toList $ Stream.fromAhead $ do -- x <- Stream.fromList [1,2] -- foreach x in stream -- y <- Stream.fromList [2,4] -- foreach y in stream -- Stream.fromEffect $ delay (x + y) -- :} -- 3 sec -- 4 sec -- 5 sec -- 6 sec -- [3,5,4,6] ---- -- The behavior can be explained as follows. All the iterations -- corresponding to the element 1 in the first stream constitute -- one output stream and all the iterations corresponding to 2 -- constitute another output stream and these two output streams are -- merged using ahead. -- -- Since: 0.3.0 (Streamly) data AheadT m a -- | For AsyncT streams: -- --
-- (<>) = async -- (>>=) = flip . concatMapWith async ---- -- A single Monad bind behaves like a for loop with -- iterations of the loop executed concurrently a la the async -- combinator, producing results and side effects of iterations out of -- order: -- --
-- >>> :{ -- Stream.toList $ Stream.fromAsync $ do -- x <- Stream.fromList [2,1] -- foreach x in stream -- Stream.fromEffect $ delay x -- :} -- 1 sec -- 2 sec -- [1,2] ---- -- Nested monad binds behave like nested for loops with nested -- iterations executed concurrently, a la the async combinator: -- --
-- >>> :{ -- Stream.toList $ Stream.fromAsync $ do -- x <- Stream.fromList [1,2] -- foreach x in stream -- y <- Stream.fromList [2,4] -- foreach y in stream -- Stream.fromEffect $ delay (x + y) -- :} -- 3 sec -- 4 sec -- 5 sec -- 6 sec -- [3,4,5,6] ---- -- The behavior can be explained as follows. All the iterations -- corresponding to the element 1 in the first stream constitute -- one output stream and all the iterations corresponding to 2 -- constitute another output stream and these two output streams are -- merged using async. -- -- Since: 0.1.0 (Streamly) data AsyncT m a -- | For WAsyncT streams: -- --
-- (<>) = wAsync -- (>>=) = flip . concatMapWith wAsync ---- -- A single Monad bind behaves like a for loop with -- iterations of the loop executed concurrently a la the wAsync -- combinator, producing results and side effects of iterations out of -- order: -- --
-- >>> :{ -- Stream.toList $ Stream.fromWAsync $ do -- x <- Stream.fromList [2,1] -- foreach x in stream -- Stream.fromEffect $ delay x -- :} -- 1 sec -- 2 sec -- [1,2] ---- -- Nested monad binds behave like nested for loops with nested -- iterations executed concurrently, a la the wAsync combinator: -- --
-- >>> :{ -- Stream.toList $ Stream.fromWAsync $ do -- x <- Stream.fromList [1,2] -- foreach x in stream -- y <- Stream.fromList [2,4] -- foreach y in stream -- Stream.fromEffect $ delay (x + y) -- :} -- 3 sec -- 4 sec -- 5 sec -- 6 sec -- [3,4,5,6] ---- -- The behavior can be explained as follows. All the iterations -- corresponding to the element 1 in the first stream constitute -- one WAsyncT output stream and all the iterations corresponding -- to 2 constitute another WAsyncT output stream and -- these two output streams are merged using wAsync. -- -- The W in the name stands for wide or breadth wise -- scheduling in contrast to the depth wise scheduling behavior of -- AsyncT. -- -- Since: 0.2.0 (Streamly) data WAsyncT m a -- | For ParallelT streams: -- --
-- (<>) = parallel -- (>>=) = flip . concatMapWith parallel ---- -- See AsyncT, ParallelT is similar except that all -- iterations are strictly concurrent while in AsyncT it depends -- on the consumer demand and available threads. See parallel -- for more details. -- -- Since: 0.1.0 (Streamly) -- -- Since: 0.7.0 (maxBuffer applies to ParallelT streams) data ParallelT m a -- | For ZipSerialM streams: -- --
-- (<>) = serial -- (*) = 'Streamly.Prelude.serial.zipWith' id ---- -- Applicative evaluates the streams being zipped serially: -- --
-- >>> s1 = Stream.fromFoldable [1, 2] -- -- >>> s2 = Stream.fromFoldable [3, 4] -- -- >>> s3 = Stream.fromFoldable [5, 6] -- -- >>> Stream.toList $ Stream.fromZipSerial $ (,,) <$> s1 <*> s2 <*> s3 -- [(1,3,5),(2,4,6)] ---- -- Since: 0.2.0 (Streamly) data ZipSerialM m a -- | For ZipAsyncM streams: -- --
-- (<>) = serial -- (*) = 'Streamly.Prelude.serial.zipAsyncWith' id ---- -- Applicative evaluates the streams being zipped concurrently, the -- following would take half the time that it would take in serial -- zipping: -- --
-- >>> s = Stream.fromFoldableM $ Prelude.map delay [1, 1, 1] -- -- >>> Stream.toList $ Stream.fromZipAsync $ (,) <$> s <*> s -- ... -- [(1,1),(1,1),(1,1)] ---- -- Since: 0.2.0 (Streamly) data ZipAsyncM m a -- | A serial IO stream of elements of type a. See SerialT -- documentation for more details. -- -- Since: 0.2.0 (Streamly) type Serial = SerialT IO -- | An interleaving serial IO stream of elements of type a. See -- WSerialT documentation for more details. -- -- Since: 0.2.0 (Streamly) type WSerial = WSerialT IO -- | A serial IO stream of elements of type a with concurrent -- lookahead. See AheadT documentation for more details. -- -- Since: 0.3.0 (Streamly) type Ahead = AheadT IO -- | A demand driven left biased parallely composing IO stream of elements -- of type a. See AsyncT documentation for more details. -- -- Since: 0.2.0 (Streamly) type Async = AsyncT IO -- | A round robin parallely composing IO stream of elements of type -- a. See WAsyncT documentation for more details. -- -- Since: 0.2.0 (Streamly) type WAsync = WAsyncT IO -- | A parallely composing IO stream of elements of type a. See -- ParallelT documentation for more details. -- -- Since: 0.2.0 (Streamly) type Parallel = ParallelT IO -- | An IO stream whose applicative instance zips streams serially. -- -- Since: 0.2.0 (Streamly) type ZipSerial = ZipSerialM IO -- | An IO stream whose applicative instance zips streams wAsyncly. -- -- Since: 0.2.0 (Streamly) type ZipAsync = ZipAsyncM IO -- | A monad that can perform concurrent or parallel IO operations. Streams -- that can be composed concurrently require the underlying monad to be -- MonadAsync. type MonadAsync m = (MonadIO m, MonadBaseControl IO m, MonadThrow m) fromStream :: (IsStream t, Monad m) => Stream m a -> t m a toStream :: (IsStream t, Monad m) => t m a -> Stream m a fromStreamK :: IsStream t => StreamK m a -> t m a toStreamK :: IsStream t => t m a -> StreamK m a -- | Class of types that can represent a stream of elements of some type -- a in some monad m. -- -- Since: 0.2.0 (Streamly) class (forall m a. MonadAsync m => Semigroup (t m a), forall m a. MonadAsync m => Monoid (t m a), forall m. Monad m => Functor (t m), forall m. MonadAsync m => Applicative (t m)) => IsStream t -- | Fix the type of a polymorphic stream as SerialT. -- -- Since: 0.1.0 (Streamly) fromSerial :: IsStream t => SerialT m a -> t m a -- | Fix the type of a polymorphic stream as WSerialT. -- -- Since: 0.2.0 (Streamly) fromWSerial :: IsStream t => WSerialT m a -> t m a -- | Fix the type of a polymorphic stream as AsyncT. -- -- Since: 0.1.0 (Streamly) fromAsync :: IsStream t => AsyncT m a -> t m a -- | Fix the type of a polymorphic stream as AheadT. -- -- Since: 0.3.0 (Streamly) fromAhead :: IsStream t => AheadT m a -> t m a -- | Fix the type of a polymorphic stream as WAsyncT. -- -- Since: 0.2.0 (Streamly) fromWAsync :: IsStream t => WAsyncT m a -> t m a -- | Fix the type of a polymorphic stream as ParallelT. -- -- Since: 0.1.0 (Streamly) fromParallel :: IsStream t => ParallelT m a -> t m a -- | Fix the type of a polymorphic stream as ZipSerialM. -- -- Since: 0.2.0 (Streamly) fromZipSerial :: IsStream t => ZipSerialM m a -> t m a -- | Fix the type of a polymorphic stream as ZipAsyncM. -- -- Since: 0.2.0 (Streamly) fromZipAsync :: IsStream t => ZipAsyncM m a -> t m a -- | Adapt any specific stream type to any other specific stream type. -- -- Since: 0.1.0 (Streamly) adapt :: (IsStream t1, IsStream t2) => t1 m a -> t2 m a -- | Same as fromPure yield :: IsStream t => a -> t m a -- | Same as fromEffect yieldM :: (Monad m, IsStream t) => m a -> t m a -- | Strict left scan with an extraction function. Like scanl', but -- applies a user supplied extraction function (the third argument) at -- each step. This is designed to work with the foldl library. -- The suffix x is a mnemonic for extraction. -- -- Since 0.2.0 -- -- Since: 0.7.0 (Monad m constraint) scanx :: (IsStream t, Monad m) => (x -> a -> x) -> x -> (x -> b) -> t m a -> t m b -- | Strict left fold with an extraction function. Like the standard strict -- left fold, but applies a user supplied extraction function (the third -- argument) to the folded value at the end. This is designed to work -- with the foldl library. The suffix x is a mnemonic -- for extraction. foldx :: Monad m => (x -> a -> x) -> x -> (x -> b) -> SerialT m a -> m b -- | Like foldx, but with a monadic step function. foldxM :: Monad m => (x -> a -> m x) -> m x -> (x -> m b) -> SerialT m a -> m b -- | Lazy right fold for non-empty streams, using first element as the -- starting value. Returns Nothing if the stream is empty. foldr1 :: Monad m => (a -> a -> a) -> SerialT m a -> m (Maybe a) -- | Run a stream, discarding the results. By default it interprets the -- stream as SerialT, to run other types of streams use the type -- adapting combinators for example runStream . -- fromAsync. runStream :: Monad m => SerialT m a -> m () -- |
-- runN n = runStream . take n ---- -- Run maximum up to n iterations of a stream. runN :: Monad m => Int -> SerialT m a -> m () -- |
-- runWhile p = runStream . takeWhile p ---- -- Run a stream as long as the predicate holds true. runWhile :: Monad m => (a -> Bool) -> SerialT m a -> m () -- | Read lines from an IO Handle into a stream of Strings. fromHandle :: (IsStream t, MonadIO m) => Handle -> t m String -- |
-- toHandle h = D.mapM_ $ hPutStrLn h ---- -- Write a stream of Strings to an IO Handle. toHandle :: MonadIO m => Handle -> SerialT m String -> m () concatUnfold :: (IsStream t, Monad m) => Unfold m a b -> t m a -> t m b