-- Hoogle documentation, generated by Haddock
-- See Hoogle, http://www.haskell.org/hoogle/


-- | Beautiful Streaming, Concurrent and Reactive Composition
--   
--   Streamly, short for streaming concurrently, provides monadic streams,
--   with a simple API, almost identical to standard lists, and an in-built
--   support for concurrency. By using stream-style combinators on stream
--   composition, streams can be generated, merged, chained, mapped,
--   zipped, and consumed concurrently – providing a generalized high level
--   programming framework unifying streaming and concurrency. Controlled
--   concurrency allows even infinite streams to be evaluated concurrently.
--   Concurrency is auto scaled based on feedback from the stream consumer.
--   The programmer does not have to be aware of threads, locking or
--   synchronization to write scalable concurrent programs.
--   
--   The basic streaming functionality of streamly is equivalent to that
--   provided by streaming libraries like <a>vector</a>, <a>streaming</a>,
--   <a>pipes</a>, and <a>conduit</a>. In addition to providing streaming
--   functionality, streamly subsumes the functionality of list transformer
--   libraries like <tt>pipes</tt> or <a>list-t</a> and also the logic
--   programming library <a>logict</a>. On the concurrency side, it
--   subsumes the functionality of the <a>async</a> package. Because it
--   supports streaming with concurrency we can write FRP applications
--   similar in concept to <a>Yampa</a> or <a>reflex</a>.
--   
--   For file IO, currently the library provides only one API to stream the
--   lines in the file as Strings. Future versions will provide better
--   streaming file IO options. Streamly interworks with the popular
--   streaming libraries, see the interworking section in
--   <a>Streamly.Tutorial</a>.
--   
--   Why use streamly?
--   
--   <ul>
--   <li><i>Simplicity</i>: Simple list like streaming API, if you know how
--   to use lists then you know how to use streamly. This library is built
--   with simplicity and ease of use as a primary design goal.</li>
--   <li><i>Concurrency</i>: Simple, powerful, and scalable concurrency.
--   Concurrency is built-in, and not intrusive, concurrent programs are
--   written exactly the same way as non-concurrent ones.</li>
--   <li><i>Generality</i>: Unifies functionality provided by several
--   disparate packages (streaming, concurrency, list transformer, logic
--   programming, reactive programming) in a concise API.</li>
--   <li><i>Performance</i>: Streamly is designed for high performance. See
--   <a>streaming-benchmarks</a> for a comparison of popular streaming
--   libraries on micro-benchmarks.</li>
--   </ul>
--   
--   Where to find more information:
--   
--   <ul>
--   <li><tt>README</tt> shipped with the package for a quick overview</li>
--   <li><a>Streamly.Tutorial</a> module in the haddock documentation for a
--   detailed introduction</li>
--   <li><tt>examples</tt> directory in the package for some simple
--   practical examples</li>
--   </ul>
@package streamly
@version 0.3.0


-- | This module is designed to be imported qualified:
--   
--   <pre>
--   import qualified Streamly.Prelude as S
--   </pre>
--   
--   Functions with the suffix <tt>M</tt> are general functions that work
--   on monadic arguments. The corresponding functions without the suffix
--   <tt>M</tt> work on pure arguments and can in general be derived from
--   their monadic versions but are provided for convenience and for
--   consistency with other pure APIs in the <tt>base</tt> package.
--   
--   Functions having a <a>MonadAsync</a> constraint work concurrently when
--   used with appropriate stream type combinator. Please be careful to not
--   use <a>parallely</a> with infinite streams.
--   
--   Deconstruction and folds accept a <a>SerialT</a> type instead of a
--   polymorphic type to ensure that streams always have a concrete
--   monomorphic type by default, reducing type errors. In case you want to
--   use any other type of stream you can use one of the type combinators
--   provided in the <a>Streamly</a> module to convert the stream type.
module Streamly.Prelude

-- | An empty stream.
--   
--   <pre>
--   &gt; toList nil
--   []
--   </pre>
nil :: IsStream t => t m a

-- | Constructs a stream by adding a monadic action at the head of an
--   existing stream. For example:
--   
--   <pre>
--   &gt; toList $ getLine `consM` getLine `consM` nil
--   hello
--   world
--   ["hello","world"]
--   </pre>
--   
--   <i>Concurrent (do not use <a>parallely</a> to construct infinite
--   streams)</i>
consM :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a
infixr 5 `consM`

-- | Operator equivalent of <a>consM</a>. We can read it as "<tt>parallel
--   colon</tt>" to remember that <tt>|</tt> comes before <tt>:</tt>.
--   
--   <pre>
--   &gt; toList $ getLine |: getLine |: nil
--   hello
--   world
--   ["hello","world"]
--   </pre>
--   
--   <pre>
--   let delay = threadDelay 1000000 &gt;&gt; print 1
--   runStream $ serially  $ delay |: delay |: delay |: nil
--   runStream $ parallely $ delay |: delay |: delay |: nil
--   </pre>
--   
--   <i>Concurrent (do not use <a>parallely</a> to construct infinite
--   streams)</i>
(|:) :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a
infixr 5 |:

-- | Construct a stream by adding a pure value at the head of an existing
--   stream. For pure values it can be faster than <a>consM</a>. For
--   example:
--   
--   <pre>
--   &gt; toList $ 1 `cons` 2 `cons` 3 `cons` nil
--   [1,2,3]
--   </pre>
cons :: IsStream t => a -> t m a -> t m a
infixr 5 `cons`

-- | Operator equivalent of <a>cons</a>.
--   
--   <pre>
--   &gt; toList $ 1 .: 2 .: 3 .: nil
--   [1,2,3]
--   </pre>
(.:) :: IsStream t => a -> t m a -> t m a
infixr 5 .:

-- | Build a stream by unfolding a <i>pure</i> 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 <a>Nothing</a> and the
--   stream ends. For example,
--   
--   <pre>
--   let f b =
--           if b &gt; 3
--           then Nothing
--           else Just (b, b + 1)
--   in toList $ unfoldr f 0
--   </pre>
--   
--   <pre>
--   [0,1,2,3]
--   </pre>
unfoldr :: IsStream t => (b -> Maybe (a, b)) -> b -> t m a

-- | Build a stream by unfolding a <i>monadic</i> 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 <a>Nothing</a> and
--   the stream ends. For example,
--   
--   <pre>
--   let f b =
--           if b &gt; 3
--           then return Nothing
--           else print b &gt;&gt; return (Just (b, b + 1))
--   in runStream $ unfoldrM f 0
--   </pre>
--   
--   <pre>
--   0
--   1
--   2
--   3
--   </pre>
--   
--   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.
--   
--   <pre>
--   (asyncly $ S.unfoldrM (\n -&gt; liftIO (threadDelay 1000000) &gt;&gt; return (Just (n, n + 1))) 0)
--       &amp; S.foldlM' (\_ a -&gt; threadDelay 1000000 &gt;&gt; print a) ()
--   </pre>
--   
--   <i>Concurrent</i>
--   
--   <i>Since: 0.1.0</i>
unfoldrM :: (IsStream t, MonadAsync m) => (b -> m (Maybe (a, b))) -> b -> t m a

-- | Create a singleton stream by executing a monadic action once. Same as
--   <tt>m `consM` nil</tt> but more efficient.
--   
--   <pre>
--   &gt; toList $ once getLine
--   hello
--   ["hello"]
--   </pre>
once :: (IsStream t, Monad m) => m a -> t m a

-- | Generate a stream by performing a monadic action <tt>n</tt> times.
--   
--   <pre>
--   runStream $ serially $ S.replicateM 10 $ (threadDelay 1000000 &gt;&gt; print 1)
--   runStream $ asyncly  $ S.replicateM 10 $ (threadDelay 1000000 &gt;&gt; print 1)
--   </pre>
--   
--   <i>Concurrent</i>
replicateM :: (IsStream t, MonadAsync m) => Int -> m a -> t m a

-- | Generate a stream by repeatedly executing a monadic action forever.
--   
--   <pre>
--   runStream $ serially $ S.take 10 $ S.repeatM $ (threadDelay 1000000 &gt;&gt; print 1)
--   runStream $ asyncly  $ S.take 10 $ S.repeatM $ (threadDelay 1000000 &gt;&gt; print 1)
--   </pre>
--   
--   <i>Concurrent, infinite (do not use with <a>parallely</a>)</i>
repeatM :: (IsStream t, MonadAsync m) => m a -> t m a

-- | Iterate a pure function from a seed value, streaming the results
--   forever.
iterate :: IsStream t => (a -> a) -> a -> t m a

-- | Iterate a monadic function from a seed value, streaming the results
--   forever.
--   
--   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.
--   
--   <pre>
--   runStream $ serially $ S.take 10 $ S.iterateM
--        (\x -&gt; threadDelay 1000000 &gt;&gt; print x &gt;&gt; return (x + 1)) 0
--   
--   runStream $ asyncly  $ S.take 10 $ S.iterateM
--        (\x -&gt; threadDelay 1000000 &gt;&gt; print x &gt;&gt; return (x + 1)) 0
--   </pre>
--   
--   <i>Concurrent</i>
iterateM :: (IsStream t, MonadAsync m) => (a -> m a) -> a -> t m a

-- | Construct a stream from a <a>Foldable</a> containing pure values.
fromFoldable :: (IsStream t, Foldable f) => f a -> t m a

-- | Construct a stream from a <a>Foldable</a> containing monadic actions.
--   
--   <pre>
--   runStream $ serially $ S.fromFoldableM $ replicate 10 (threadDelay 1000000 &gt;&gt; print 1)
--   runStream $ asyncly  $ S.fromFoldableM $ replicate 10 (threadDelay 1000000 &gt;&gt; print 1)
--   </pre>
--   
--   <i>Concurrent (do not use with <a>parallely</a> on infinite
--   containers)</i>
fromFoldableM :: (IsStream t, MonadAsync m, Foldable f) => f (m a) -> t m a

-- | Decompose a stream into its head and tail. If the stream is empty,
--   returns <a>Nothing</a>. If the stream is non-empty, returns <tt>Just
--   (a, ma)</tt>, where <tt>a</tt> is the head of the stream and
--   <tt>ma</tt> its tail.
uncons :: (IsStream t, Monad m) => SerialT m a -> m (Maybe (a, t m a))

-- | Lazy right associative fold. For example, to fold a stream into a
--   list:
--   
--   <pre>
--   &gt;&gt; runIdentity $ foldr (:) [] (serially $ fromFoldable [1,2,3])
--   [1,2,3]
--   </pre>
foldr :: Monad m => (a -> b -> b) -> b -> SerialT m a -> m b

-- | Lazy right fold with a monadic step function. For example, to fold a
--   stream into a list:
--   
--   <pre>
--   &gt;&gt; runIdentity $ foldrM (\x xs -&gt; return (x : xs)) [] (serially $ fromFoldable [1,2,3])
--   [1,2,3]
--   </pre>
foldrM :: Monad m => (a -> b -> m b) -> b -> SerialT m a -> m b

-- | Strict left associative fold.
foldl' :: Monad m => (b -> a -> b) -> b -> SerialT m a -> m b

-- | Like <a>foldl'</a> but with a monadic step function.
foldlM' :: Monad m => (b -> a -> m b) -> b -> SerialT 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 <tt>foldl</tt> library. The suffix <tt>x</tt> is a mnemonic
--   for extraction.
foldx :: Monad m => (x -> a -> x) -> x -> (x -> b) -> SerialT m a -> m b

-- | Like <a>foldx</a>, but with a monadic step function.
foldxM :: Monad m => (x -> a -> m x) -> m x -> (x -> m b) -> SerialT m a -> m b

-- | Apply a monadic action to each element of the stream and discard the
--   output of the action.
mapM_ :: Monad m => (a -> m b) -> SerialT m a -> m ()

-- | Convert a stream into a list in the underlying monad.
toList :: Monad m => SerialT m a -> m [a]

-- | Determine whether all elements of a stream satisfy a predicate.
all :: Monad m => (a -> Bool) -> SerialT m a -> m Bool

-- | Determine whether any of the elements of a stream satisfy a predicate.
any :: Monad m => (a -> Bool) -> SerialT m a -> m Bool

-- | Extract the first element of the stream, if any.
head :: Monad m => SerialT m a -> m (Maybe a)

-- | 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 the last element of the stream, if any.
last :: Monad m => SerialT m a -> m (Maybe a)

-- | Determine whether the stream is empty.
null :: Monad m => SerialT m a -> m Bool

-- | Determine the length of the stream.
length :: Monad m => SerialT m a -> m Int

-- | Determine whether an element is present in the stream.
elem :: (Monad m, Eq a) => a -> SerialT m a -> m Bool

-- | Determine whether an element is not present in the stream.
notElem :: (Monad m, Eq a) => a -> SerialT m a -> m Bool

-- | 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.
minimum :: (Monad m, Ord a) => SerialT m a -> m (Maybe a)

-- | Determine the sum of all elements of a stream of numbers
sum :: (Monad m, Num a) => SerialT m a -> m a

-- | Determine the product of all elements of a stream of numbers
product :: (Monad m, Num a) => SerialT m a -> m a

-- | Strict left scan. Like <a>foldl'</a>, but returns the folded value at
--   each step, generating a stream of all intermediate fold results. The
--   first element of the stream is the user supplied initial value, and
--   the last element of the stream is the same as the result of
--   <a>foldl'</a>.
scanl' :: IsStream t => (b -> a -> b) -> b -> t m a -> t m b

-- | Strict left scan with an extraction function. Like <a>scanl'</a>, but
--   applies a user supplied extraction function (the third argument) at
--   each step. This is designed to work with the <tt>foldl</tt> library.
--   The suffix <tt>x</tt> is a mnemonic for extraction.
scanx :: IsStream t => (x -> a -> x) -> x -> (x -> b) -> t m a -> t m b

-- | Include only those elements that pass a predicate.
filter :: IsStream t => (a -> Bool) -> t m a -> t m a

-- | Take first <tt>n</tt> elements from the stream and discard the rest.
take :: IsStream t => Int -> t m a -> t m a

-- | End the stream as soon as the predicate fails on an element.
takeWhile :: IsStream t => (a -> Bool) -> t m a -> t m a

-- | Discard first <tt>n</tt> elements from the stream and take the rest.
drop :: IsStream t => 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 => (a -> Bool) -> t m a -> t m a

-- | Returns the elements of the stream in reverse order. The stream must
--   be finite.
reverse :: (IsStream t) => t m a -> t m a

-- | Replace each element of the stream with the result of a monadic action
--   applied on the element.
--   
--   <pre>
--   runStream $ S.replicateM 10 (return 1)
--             &amp; (serially . S.mapM (\x -&gt; threadDelay 1000000 &gt;&gt; print x))
--   
--   runStream $ S.replicateM 10 (return 1)
--             &amp; (asyncly . S.mapM (\x -&gt; threadDelay 1000000 &gt;&gt; print x))
--   </pre>
--   
--   <i>Concurrent (do not use with <a>parallely</a> on infinite
--   streams)</i>
mapM :: (IsStream t, MonadAsync m) => (a -> m b) -> t m a -> t m b

-- | Map a <a>Maybe</a> returning function to a stream, filter out the
--   <a>Nothing</a> elements, and return a stream of values extracted from
--   <a>Just</a>.
mapMaybe :: (IsStream t) => (a -> Maybe b) -> t m a -> t m b

-- | Like <a>mapMaybe</a> but maps a monadic function.
--   
--   <i>Concurrent (do not use with <a>parallely</a> on infinite
--   streams)</i>
mapMaybeM :: (IsStream t, MonadAsync m, Functor (t m)) => (a -> m (Maybe b)) -> t m a -> t m b

-- | Reduce a stream of monadic actions to a stream of the output of those
--   actions.
--   
--   <pre>
--   runStream $ S.replicateM 10 (return $ threadDelay 1000000 &gt;&gt; print 1)
--             &amp; (serially . S.sequence)
--   
--   runStream $ S.replicateM 10 (return $ threadDelay 1000000 &gt;&gt; print 1)
--             &amp; (asyncly . S.sequence)
--   </pre>
--   
--   <i>Concurrent (do not use with <a>parallely</a> on infinite
--   streams)</i>
sequence :: (IsStream t, MonadAsync m) => t m (m a) -> t m a

-- | Zip two streams serially using a pure zipping function.
zipWith :: IsStream t => (a -> b -> c) -> t m a -> t m b -> t m c

-- | Zip two streams serially using a monadic zipping function.
zipWithM :: IsStream t => (a -> b -> t m c) -> t m a -> t m b -> t m c

-- | Zip two streams concurrently (i.e. both the elements being zipped are
--   generated concurrently) using a pure zipping function.
zipAsyncWith :: (IsStream t, MonadAsync m) => (a -> b -> c) -> t m a -> t m b -> t m c

-- | Zip two streams asyncly (i.e. both the elements being zipped are
--   generated concurrently) using a monadic zipping function.
zipAsyncWithM :: (IsStream t, MonadAsync m) => (a -> b -> t m c) -> t m a -> t m b -> t m c

-- | Read lines from an IO Handle into a stream of Strings.
fromHandle :: (IsStream t, MonadIO m) => Handle -> t m String

-- | Write a stream of Strings to an IO Handle.
toHandle :: MonadIO m => Handle -> SerialT m String -> m ()

-- | Same as <a>fromFoldable</a>.

-- | <i>Deprecated: Please use fromFoldable instead.</i>
each :: (IsStream t, Foldable f) => f a -> t m a


-- | <i>Deprecated: Please use scanx instead.</i>
scan :: IsStream t => (x -> a -> x) -> x -> (x -> b) -> t m a -> t m b


-- | <i>Deprecated: Please use foldx instead.</i>
foldl :: Monad m => (x -> a -> x) -> x -> (x -> b) -> SerialT m a -> m b


-- | <i>Deprecated: Please use foldxM instead.</i>
foldlM :: Monad m => (x -> a -> m x) -> m x -> (x -> m b) -> SerialT m a -> m b


-- | The way a list represents a sequence of pure values, a stream
--   represents a sequence of monadic actions. The monadic stream API
--   offered by Streamly is very close to the Haskell <a>Prelude</a> pure
--   lists' API, it can be considered as a natural extension of lists to
--   monadic actions. Streamly streams provide concurrent composition and
--   merging of streams. It can be considered as a concurrent list
--   transformer. In contrast to the <a>Prelude</a> lists, merging or
--   appending streams of arbitrary length is scalable and inexpensive.
--   
--   The basic stream type is <a>Serial</a>, it represents a sequence of IO
--   actions, and is a <a>Monad</a>. The type <a>SerialT</a> is a monad
--   transformer that can represent a sequence of actions in an arbitrary
--   monad. The type <a>Serial</a> is in fact a synonym for <tt>SerialT
--   IO</tt>. There are a few more types similar to <a>SerialT</a>, all of
--   them represent a stream and differ only in the <a>Semigroup</a>,
--   <a>Applicative</a> and <a>Monad</a> compositions of the stream.
--   <a>Serial</a> and <a>WSerial</a> types compose serially whereas
--   <a>Async</a> and <a>WAsync</a> types compose concurrently. All these
--   types can be freely inter-converted using type combinators without any
--   cost. You can freely switch to any type of composition at any point in
--   the program. When no type annotation or explicit stream type
--   combinators are used, the default stream type is inferred as
--   <a>Serial</a>.
--   
--   Here is a simple console echo program example:
--   
--   <pre>
--   &gt; runStream $ S.repeatM getLine &amp; S.mapM putStrLn
--   </pre>
--   
--   For more details please see the <a>Streamly.Tutorial</a> module and
--   the examples directory in this package.
--   
--   This module exports stream types, instances and some basic operations.
--   Functionality exported by this module include:
--   
--   <ul>
--   <li>Semigroup append (<a>&lt;&gt;</a>) instances as well as explicit
--   operations for merging streams</li>
--   <li>Monad and Applicative instances for looping over streams</li>
--   <li>Zip Applicatives for zipping streams</li>
--   <li>Stream type combinators to convert between different composition
--   styles</li>
--   <li>Some basic utilities to run and fold streams</li>
--   </ul>
--   
--   See the <a>Streamly.Prelude</a> module for comprehensive APIs for
--   construction, generation, elimination and transformation of streams.
--   
--   This module is designed to be imported unqualified:
--   
--   <pre>
--   import Streamly
--   </pre>
module Streamly

-- | A monad that can perform concurrent or parallel IO operations. Streams
--   that can be composed concurrently require the underlying monad to be
--   <a>MonadAsync</a>.
type MonadAsync m = (MonadIO m, MonadBaseControl IO m, MonadThrow m)

-- | Deep serial composition or serial composition with depth first
--   traversal. The <a>Semigroup</a> instance of <a>SerialT</a> appends two
--   streams serially in a depth first manner, yielding all elements from
--   the first stream, and then all elements from the second stream.
--   
--   <pre>
--   import Streamly
--   import qualified <a>Streamly.Prelude</a> as S
--   
--   main = (<tt>toList</tt> . <a>serially</a> $ (fromFoldable [1,2]) &lt;&gt; (fromFoldable [3,4])) &gt;&gt;= print
--   </pre>
--   
--   <pre>
--   [1,2,3,4]
--   </pre>
--   
--   The <a>Monad</a> instance runs the <i>monadic continuation</i> for
--   each element of the stream, serially.
--   
--   <pre>
--   main = <a>runStream</a> . <a>serially</a> $ do
--       x &lt;- return 1 &lt;&gt; return 2
--       S.once $ print x
--   </pre>
--   
--   <pre>
--   1
--   2
--   </pre>
--   
--   <a>SerialT</a> nests streams serially in a depth first manner.
--   
--   <pre>
--   main = <a>runStream</a> . <a>serially</a> $ do
--       x &lt;- return 1 &lt;&gt; return 2
--       y &lt;- return 3 &lt;&gt; return 4
--       S.once $ print (x, y)
--   </pre>
--   
--   <pre>
--   (1,3)
--   (1,4)
--   (2,3)
--   (2,4)
--   </pre>
--   
--   This behavior of <a>SerialT</a> is exactly like a list transformer. We
--   call the monadic code being run for each element of the stream a
--   monadic continuation. In imperative paradigm we can think of this
--   composition as nested <tt>for</tt> loops and the monadic continuation
--   is the body of the loop. The loop iterates for all elements of the
--   stream.
--   
--   The <a>serially</a> combinator can be omitted as the default stream
--   type is <a>SerialT</a>. Note that serial composition with depth first
--   traversal can be used to combine an infinite number of streams as it
--   explores only one stream at a time.
data SerialT m a

-- | Wide serial composition or serial composition with a breadth first
--   traversal. The <a>Semigroup</a> instance of <a>WSerialT</a> traverses
--   the two streams in a breadth first manner. In other words, it
--   interleaves two streams, yielding one element from each stream
--   alternately.
--   
--   <pre>
--   import Streamly
--   import qualified <a>Streamly.Prelude</a> as S
--   
--   main = (<tt>toList</tt> . <a>wSerially</a> $ (fromFoldable [1,2]) &lt;&gt; (fromFoldable [3,4])) &gt;&gt;= print
--   </pre>
--   
--   <pre>
--   [1,3,2,4]
--   </pre>
--   
--   Similarly, the <a>Monad</a> instance interleaves the iterations of the
--   inner and the outer loop, nesting loops in a breadth first manner.
--   
--   <pre>
--   main = <a>runStream</a> . <a>wSerially</a> $ do
--       x &lt;- return 1 &lt;&gt; return 2
--       y &lt;- return 3 &lt;&gt; return 4
--       S.once $ print (x, y)
--   </pre>
--   
--   <pre>
--   (1,3)
--   (2,3)
--   (1,4)
--   (2,4)
--   </pre>
--   
--   Note that a serial composition with breadth first traversal can only
--   combine a finite number of streams as it needs to retain state for
--   each unfinished stream.
data WSerialT m a

-- | Deep ahead composition or ahead composition with depth first
--   traversal. The semigroup composition of <a>AheadT</a> appends streams
--   in a depth first manner just like <a>SerialT</a> except that it can
--   produce elements concurrently ahead of time. It is like <a>AsyncT</a>
--   except that <a>AsyncT</a> produces the output as it arrives whereas
--   <a>AheadT</a> orders the output in the traversal order.
--   
--   <pre>
--   main = (<tt>toList</tt> . <a>aheadly</a> $ (fromFoldable [1,2]) &lt;&gt; (fromFoldable [3,4])) &gt;&gt;= print
--   </pre>
--   
--   <pre>
--   [1,2,3,4]
--   </pre>
--   
--   Any exceptions generated by a constituent stream are propagated to the
--   output stream.
--   
--   Similarly, the monad instance of <a>AheadT</a> may run each iteration
--   concurrently ahead of time but presents the results in the same order
--   as <a>SerialT</a>.
--   
--   <pre>
--   import <a>Streamly</a>
--   import qualified <a>Streamly.Prelude</a> as S
--   import Control.Concurrent
--   
--   main = <a>runStream</a> . <a>aheadly</a> $ do
--       n &lt;- return 3 &lt;&gt; return 2 &lt;&gt; return 1
--       S.once $ do
--            threadDelay (n * 1000000)
--            myThreadId &gt;&gt;= \tid -&gt; putStrLn (show tid ++ ": Delay " ++ show n)
--   </pre>
--   
--   <pre>
--   ThreadId 40: Delay 1
--   ThreadId 39: Delay 2
--   ThreadId 38: Delay 3
--   </pre>
--   
--   All iterations may run in the same thread if they do not block.
--   
--   Note that ahead composition with depth first traversal can be used to
--   combine infinite number of streams as it explores only a bounded
--   number of streams at a time.
data AheadT m a

-- | Deep async composition or async composition with depth first
--   traversal. In a left to right <a>Semigroup</a> composition it tries to
--   yield elements from the left stream as long as it can, but it can run
--   the right stream in parallel if it needs to, based on demand. The
--   right stream can be run if the left stream blocks on IO or cannot
--   produce elements fast enough for the consumer.
--   
--   <pre>
--   main = (<tt>toList</tt> . <a>asyncly</a> $ (fromFoldable [1,2]) &lt;&gt; (fromFoldable [3,4])) &gt;&gt;= print
--   </pre>
--   
--   <pre>
--   [1,2,3,4]
--   </pre>
--   
--   Any exceptions generated by a constituent stream are propagated to the
--   output stream. The output and exceptions from a single stream are
--   guaranteed to arrive in the same order in the resulting stream as they
--   were generated in the input stream. However, the relative ordering of
--   elements from different streams in the resulting stream can vary
--   depending on scheduling and generation delays.
--   
--   Similarly, the monad instance of <a>AsyncT</a> <i>may</i> run each
--   iteration concurrently based on demand. More concurrent iterations are
--   started only if the previous iterations are not able to produce enough
--   output for the consumer.
--   
--   <pre>
--   import <a>Streamly</a>
--   import qualified <a>Streamly.Prelude</a> as S
--   import Control.Concurrent
--   
--   main = <a>runStream</a> . <a>asyncly</a> $ do
--       n &lt;- return 3 &lt;&gt; return 2 &lt;&gt; return 1
--       S.once $ do
--            threadDelay (n * 1000000)
--            myThreadId &gt;&gt;= \tid -&gt; putStrLn (show tid ++ ": Delay " ++ show n)
--   </pre>
--   
--   <pre>
--   ThreadId 40: Delay 1
--   ThreadId 39: Delay 2
--   ThreadId 38: Delay 3
--   </pre>
--   
--   All iterations may run in the same thread if they do not block.
--   
--   Note that async composition with depth first traversal can be used to
--   combine infinite number of streams as it explores only a bounded
--   number of streams at a time.
data AsyncT m a

-- | Wide async composition or async composition with breadth first
--   traversal. The Semigroup instance of <a>WAsyncT</a> concurrently
--   <i>traverses</i> the composed streams using a depth first travesal or
--   in a round robin fashion, yielding elements from both streams
--   alternately.
--   
--   <pre>
--   main = (<tt>toList</tt> . <a>wAsyncly</a> $ (fromFoldable [1,2]) &lt;&gt; (fromFoldable [3,4])) &gt;&gt;= print
--   </pre>
--   
--   <pre>
--   [1,3,2,4]
--   </pre>
--   
--   Any exceptions generated by a constituent stream are propagated to the
--   output stream. The output and exceptions from a single stream are
--   guaranteed to arrive in the same order in the resulting stream as they
--   were generated in the input stream. However, the relative ordering of
--   elements from different streams in the resulting stream can vary
--   depending on scheduling and generation delays.
--   
--   Similarly, the <a>Monad</a> instance of <a>WAsyncT</a> runs <i>all</i>
--   iterations fairly concurrently using a round robin scheduling.
--   
--   <pre>
--   import <a>Streamly</a>
--   import qualified <a>Streamly.Prelude</a> as S
--   import Control.Concurrent
--   
--   main = <a>runStream</a> . <a>wAsyncly</a> $ do
--       n &lt;- return 3 &lt;&gt; return 2 &lt;&gt; return 1
--       S.once $ do
--            threadDelay (n * 1000000)
--            myThreadId &gt;&gt;= \tid -&gt; putStrLn (show tid ++ ": Delay " ++ show n)
--   </pre>
--   
--   <pre>
--   ThreadId 40: Delay 1
--   ThreadId 39: Delay 2
--   ThreadId 38: Delay 3
--   </pre>
--   
--   Unlike <a>AsyncT</a> all iterations are guaranteed to run fairly
--   concurrently, unconditionally.
--   
--   Note that async composition with breadth first traversal can only
--   combine a finite number of streams as it needs to retain state for
--   each unfinished stream.
data WAsyncT m a

-- | Async composition with simultaneous traversal of all streams.
--   
--   The Semigroup instance of <a>ParallelT</a> concurrently <i>merges</i>
--   two streams, running both strictly concurrently and yielding elements
--   from both streams as they arrive. When multiple streams are combined
--   using <a>ParallelT</a> each one is evaluated in its own thread and the
--   results produced are presented in the combined stream on a first come
--   first serve basis.
--   
--   <a>AsyncT</a> and <a>WAsyncT</a> are <i>concurrent lookahead
--   streams</i> each with a specific type of consumption pattern (depth
--   first or breadth first). Since they are lookahead, they may introduce
--   certain default latency in starting more concurrent tasks for
--   efficiency reasons or may put a default limitation on the resource
--   consumption (e.g. number of concurrent threads for lookahead). If we
--   look at the implementation detail, they both can share a pool of
--   worker threads to evaluate the streams in the desired pattern and at
--   the desired rate. However, <a>ParallelT</a> uses a separate runtime
--   thread to evaluate each stream.
--   
--   <a>WAsyncT</a> is similar to <a>ParallelT</a>, as both of them
--   evaluate the constituent streams fairly in a round robin fashion.
--   However, the key difference is that <a>WAsyncT</a> is lazy or pull
--   driven whereas <a>ParallelT</a> is strict or push driven.
--   <a>ParallelT</a> immediately starts concurrent evaluation of both the
--   streams (in separate threads) and later picks the results whereas
--   <a>WAsyncT</a> may wait for a certain latency threshold before
--   initiating concurrent evaluation of the next stream. The concurrent
--   scheduling of the next stream or the degree of concurrency is driven
--   by the feedback from the consumer. In case of <a>ParallelT</a> each
--   stream is evaluated in a separate thread and results are <i>pushed</i>
--   to a shared output buffer, the evaluation rate is controlled by
--   blocking when the buffer is full.
--   
--   Concurrent lookahead streams are generally more efficient than
--   <a>ParallelT</a> and can work pretty efficiently even for smaller
--   tasks because they do not necessarily use a separate thread for each
--   task. So they should be preferred over <a>ParallelT</a> especially
--   when efficiency is a concern and simultaneous strict evaluation is not
--   a requirement. <a>ParallelT</a> is useful for cases when the streams
--   are required to be evaluated simultaneously irrespective of how the
--   consumer consumes them e.g. when we want to race two tasks and want to
--   start both strictly at the same time or if we have timers in the
--   parallel tasks and our results depend on the timers being started at
--   the same time. We can say that <a>ParallelT</a> is almost the same
--   (modulo some implementation differences) as <a>WAsyncT</a> when the
--   latter is used with unlimited lookahead and zero latency in initiating
--   lookahead.
--   
--   <pre>
--   main = (<tt>toList</tt> . <a>parallely</a> $ (fromFoldable [1,2]) &lt;&gt; (fromFoldable [3,4])) &gt;&gt;= print
--   </pre>
--   
--   <pre>
--   [1,3,2,4]
--   </pre>
--   
--   When streams with more than one element are merged, it yields
--   whichever stream yields first without any bias, unlike the
--   <a>Async</a> style streams.
--   
--   Any exceptions generated by a constituent stream are propagated to the
--   output stream. The output and exceptions from a single stream are
--   guaranteed to arrive in the same order in the resulting stream as they
--   were generated in the input stream. However, the relative ordering of
--   elements from different streams in the resulting stream can vary
--   depending on scheduling and generation delays.
--   
--   Similarly, the <a>Monad</a> instance of <a>ParallelT</a> runs
--   <i>all</i> iterations of the loop concurrently.
--   
--   <pre>
--   import <a>Streamly</a>
--   import qualified <a>Streamly.Prelude</a> as S
--   import Control.Concurrent
--   
--   main = <a>runStream</a> . <a>parallely</a> $ do
--       n &lt;- return 3 &lt;&gt; return 2 &lt;&gt; return 1
--       S.once $ do
--            threadDelay (n * 1000000)
--            myThreadId &gt;&gt;= \tid -&gt; putStrLn (show tid ++ ": Delay " ++ show n)
--   </pre>
--   
--   <pre>
--   ThreadId 40: Delay 1
--   ThreadId 39: Delay 2
--   ThreadId 38: Delay 3
--   </pre>
--   
--   Note that parallel composition can only combine a finite number of
--   streams as it needs to retain state for each unfinished stream.
data ParallelT m a

-- | The applicative instance of <a>ZipSerialM</a> zips a number of streams
--   serially i.e. it produces one element from each stream serially and
--   then zips all those elements.
--   
--   <pre>
--   main = (toList . <a>zipSerially</a> $ (,,) &lt;$&gt; s1 &lt;*&gt; s2 &lt;*&gt; s3) &gt;&gt;= print
--       where s1 = fromFoldable [1, 2]
--             s2 = fromFoldable [3, 4]
--             s3 = fromFoldable [5, 6]
--   </pre>
--   
--   <pre>
--   [(1,3,5),(2,4,6)]
--   </pre>
--   
--   The <a>Semigroup</a> instance of this type works the same way as that
--   of <a>SerialT</a>.
data ZipSerialM m a

-- | Like <a>ZipSerialM</a> but zips in parallel, it generates all the
--   elements to be zipped concurrently.
--   
--   <pre>
--   main = (toList . <a>zipAsyncly</a> $ (,,) &lt;$&gt; s1 &lt;*&gt; s2 &lt;*&gt; s3) &gt;&gt;= print
--       where s1 = fromFoldable [1, 2]
--             s2 = fromFoldable [3, 4]
--             s3 = fromFoldable [5, 6]
--   </pre>
--   
--   <pre>
--   [(1,3,5),(2,4,6)]
--   </pre>
--   
--   The <a>Semigroup</a> instance of this type works the same way as that
--   of <a>SerialT</a>.
data ZipAsyncM m a

-- | Run a streaming composition, discard the results. By default it
--   interprets the stream as <a>SerialT</a>, to run other types of streams
--   use the type adapting combinators for example <tt>runStream .
--   <a>asyncly</a></tt>.
runStream :: Monad m => SerialT m a -> m ()

-- | Parallel function application operator for streams; just like the
--   regular function application operator <a>$</a> except that it is
--   concurrent. The following code prints a value every second even though
--   each stage adds a 1 second delay.
--   
--   <pre>
--   runStream $
--      S.mapM (\x -&gt; threadDelay 1000000 &gt;&gt; print x)
--        |$ S.repeatM (threadDelay 1000000 &gt;&gt; return 1)
--   </pre>
--   
--   <i>Concurrent</i>
(|$) :: (IsStream t, MonadAsync m) => (t m a -> t m b) -> t m a -> t m b
infixr 0 |$

-- | Parallel reverse function application operator for streams; just like
--   the regular reverse function application operator <tt>&amp;</tt>
--   except that it is concurrent.
--   
--   <pre>
--   runStream $
--         S.repeatM (threadDelay 1000000 &gt;&gt; return 1)
--      |&amp; S.mapM (\x -&gt; threadDelay 1000000 &gt;&gt; print x)
--   </pre>
--   
--   <i>Concurrent</i>
(|&) :: (IsStream t, MonadAsync m) => t m a -> (t m a -> t m b) -> t m b
infixl 1 |&

-- | Parallel function application operator; applies a <tt>run</tt> or
--   <tt>fold</tt> function to a stream such that the fold consumer and the
--   stream producer run in parallel. A <tt>run</tt> or <tt>fold</tt>
--   function reduces the stream to a value in the underlying monad. The
--   <tt>.</tt> at the end of the operator is a mnemonic for termination of
--   the stream.
--   
--   <pre>
--   S.foldlM' (\_ a -&gt; threadDelay 1000000 &gt;&gt; print a) ()
--      |$. S.repeatM (threadDelay 1000000 &gt;&gt; return 1)
--   </pre>
--   
--   <i>Concurrent</i>
(|$.) :: (IsStream t, MonadAsync m) => (t m a -> m b) -> t m a -> m b
infixr 0 |$.

-- | Parallel reverse function application operator for applying a run or
--   fold functions to a stream. Just like <a>|$.</a> except that the
--   operands are reversed.
--   
--   <pre>
--       S.repeatM (threadDelay 1000000 &gt;&gt; return 1)
--   |&amp;. S.foldlM' (\_ a -&gt; threadDelay 1000000 &gt;&gt; print a) ()
--   </pre>
--   
--   <i>Concurrent</i>
(|&.) :: (IsStream t, MonadAsync m) => t m a -> (t m a -> m b) -> m b
infixl 1 |&.

-- | Make a stream asynchronous, triggers the computation and returns a
--   stream in the underlying monad representing the output generated by
--   the original computation. The returned action is exhaustible and must
--   be drained once. If not drained fully we may have a thread blocked
--   forever and once exhausted it will always return <tt>empty</tt>.
mkAsync :: (IsStream t, MonadAsync m) => t m a -> m (t m a)

-- | Polymorphic version of the <a>Semigroup</a> operation <a>&lt;&gt;</a>
--   of <a>SerialT</a>. Appends two streams sequentially, yielding all
--   elements from the first stream, and then all elements from the second
--   stream.
serial :: IsStream t => t m a -> t m a -> t m a

-- | Polymorphic version of the <a>Semigroup</a> operation <a>&lt;&gt;</a>
--   of <a>WSerialT</a>. Interleaves two streams, yielding one element from
--   each stream alternately.
wSerial :: IsStream t => t m a -> t m a -> t m a

-- | Polymorphic version of the <a>Semigroup</a> operation <a>&lt;&gt;</a>
--   of <a>AheadT</a>. Merges two streams sequentially but with concurrent
--   lookahead.
ahead :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a

-- | Polymorphic version of the <a>Semigroup</a> operation <a>&lt;&gt;</a>
--   of <a>AsyncT</a>. Merges two streams possibly concurrently, preferring
--   the elements from the left one when available.
async :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a

-- | Polymorphic version of the <a>Semigroup</a> operation <a>&lt;&gt;</a>
--   of <a>WAsyncT</a>. Merges two streams concurrently choosing elements
--   from both fairly.
wAsync :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a

-- | Polymorphic version of the <a>Semigroup</a> operation <a>&lt;&gt;</a>
--   of <a>ParallelT</a> Merges two streams concurrently.
parallel :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a

-- | A variant of <a>fold</a> that allows you to fold a <a>Foldable</a>
--   container of streams using the specified stream sum operation.
--   
--   <pre>
--   foldWith <a>async</a> $ map return [1..3]
--   </pre>
foldWith :: (IsStream t, Foldable f) => (t m a -> t m a -> t m a) -> f (t m a) -> t m a

-- | A variant of <a>foldMap</a> that allows you to map a monadic streaming
--   action on a <a>Foldable</a> container and then fold it using the
--   specified stream sum operation.
--   
--   <pre>
--   foldMapWith <a>async</a> return [1..3]
--   </pre>
foldMapWith :: (IsStream t, Foldable f) => (t m b -> t m b -> t m b) -> (a -> t m b) -> f a -> t m b

-- | Like <a>foldMapWith</a> but with the last two arguments reversed i.e.
--   the monadic streaming function is the last argument.
forEachWith :: (IsStream t, Foldable f) => (t m b -> t m b -> t m b) -> f a -> (a -> t m b) -> t m b

-- | Class of types that can represent a stream of elements of some type
--   <tt>a</tt> in some monad <tt>m</tt>.
class IsStream t

-- | Fix the type of a polymorphic stream as <a>SerialT</a>.
serially :: IsStream t => SerialT m a -> t m a

-- | Fix the type of a polymorphic stream as <a>WSerialT</a>.
wSerially :: IsStream t => WSerialT m a -> t m a

-- | Fix the type of a polymorphic stream as <a>AsyncT</a>.
asyncly :: IsStream t => AsyncT m a -> t m a

-- | Fix the type of a polymorphic stream as <a>AheadT</a>.
aheadly :: IsStream t => AheadT m a -> t m a

-- | Fix the type of a polymorphic stream as <a>WAsyncT</a>.
wAsyncly :: IsStream t => WAsyncT m a -> t m a

-- | Fix the type of a polymorphic stream as <a>ParallelT</a>.
parallely :: IsStream t => ParallelT m a -> t m a

-- | Fix the type of a polymorphic stream as <a>ZipSerialM</a>.
zipSerially :: IsStream t => ZipSerialM m a -> t m a

-- | Fix the type of a polymorphic stream as <a>ZipAsyncM</a>.
zipAsyncly :: IsStream t => ZipAsyncM m a -> t m a

-- | Adapt any specific stream type to any other specific stream type.
adapt :: (IsStream t1, IsStream t2) => t1 m a -> t2 m a

-- | A serial IO stream of elements of type <tt>a</tt>. See <a>SerialT</a>
--   documentation for more details.
type Serial a = SerialT IO a

-- | An interleaving serial IO stream of elements of type <tt>a</tt>. See
--   <a>WSerialT</a> documentation for more details.
type WSerial a = WSerialT IO a

-- | A serial IO stream of elements of type <tt>a</tt> with concurrent
--   lookahead. See <a>AheadT</a> documentation for more details.
type Ahead a = AheadT IO a

-- | A demand driven left biased parallely composing IO stream of elements
--   of type <tt>a</tt>. See <a>AsyncT</a> documentation for more details.
type Async a = AsyncT IO a

-- | A round robin parallely composing IO stream of elements of type
--   <tt>a</tt>. See <a>WAsyncT</a> documentation for more details.
type WAsync a = WAsyncT IO a

-- | A parallely composing IO stream of elements of type <tt>a</tt>. See
--   <a>ParallelT</a> documentation for more details.
type Parallel a = ParallelT IO a

-- | An IO stream whose applicative instance zips streams serially.
type ZipSerial a = ZipSerialM IO a

-- | An IO stream whose applicative instance zips streams wAsyncly.
type ZipAsync a = ZipAsyncM IO a

-- | The class of semigroups (types with an associative binary operation).
--   
--   Instances should satisfy the associativity law:
--   
--   <ul>
--   <li><pre>x <a>&lt;&gt;</a> (y <a>&lt;&gt;</a> z) = (x <a>&lt;&gt;</a>
--   y) <a>&lt;&gt;</a> z</pre></li>
--   </ul>
class Semigroup a

-- | An associative operation.
(<>) :: Semigroup a => a -> a -> a

-- | Reduce a non-empty list with <tt>&lt;&gt;</tt>
--   
--   The default definition should be sufficient, but this can be
--   overridden for efficiency.
sconcat :: Semigroup a => NonEmpty a -> a

-- | Repeat a value <tt>n</tt> times.
--   
--   Given that this works on a <a>Semigroup</a> it is allowed to fail if
--   you request 0 or fewer repetitions, and the default definition will do
--   so.
--   
--   By making this a member of the class, idempotent semigroups and
--   monoids can upgrade this to execute in <i>O(1)</i> by picking
--   <tt>stimes = <tt>stimesIdempotent</tt></tt> or <tt>stimes =
--   <a>stimesIdempotentMonoid</a></tt> respectively.
stimes :: (Semigroup a, Integral b) => b -> a -> a

-- | Same as <a>IsStream</a>.

-- | <i>Deprecated: Please use IsStream instead.</i>
type Streaming = IsStream

-- | Same as <a>runStream</a>

-- | <i>Deprecated: Please use runStream instead.</i>
runStreaming :: (Monad m, IsStream t) => t m a -> m ()

-- | Same as <tt>runStream</tt>.

-- | <i>Deprecated: Please use runStream instead.</i>
runStreamT :: Monad m => SerialT m a -> m ()

-- | Same as <tt>runStream . wSerially</tt>.

-- | <i>Deprecated: Please use 'runStream . interleaving' instead.</i>
runInterleavedT :: Monad m => InterleavedT m a -> m ()

-- | Same as <tt>runStream . asyncly</tt>.

-- | <i>Deprecated: Please use 'runStream . asyncly' instead.</i>
runAsyncT :: Monad m => AsyncT m a -> m ()

-- | Same as <tt>runStream . parallely</tt>.

-- | <i>Deprecated: Please use 'runStream . parallely' instead.</i>
runParallelT :: Monad m => ParallelT m a -> m ()

-- | Same as <tt>runStream . zipping</tt>.

-- | <i>Deprecated: Please use 'runStream . zipSerially instead.</i>
runZipStream :: Monad m => ZipSerialM m a -> m ()

-- | Same as <tt>runStream . zippingAsync</tt>.

-- | <i>Deprecated: Please use 'runStream . zipAsyncly instead.</i>
runZipAsync :: Monad m => ZipAsyncM m a -> m ()


-- | <i>Deprecated: Please use <a>SerialT</a> instead.</i>
type StreamT = SerialT


-- | <i>Deprecated: Please use <a>WSerialT</a> instead.</i>
type InterleavedT = WSerialT


-- | <i>Deprecated: Please use <a>ZipSerialM</a> instead.</i>
type ZipStream = ZipSerialM

-- | Same as <a>wSerially</a>.

-- | <i>Deprecated: Please use wSerially instead.</i>
interleaving :: IsStream t => WSerialT m a -> t m a

-- | Same as <a>zipSerially</a>.

-- | <i>Deprecated: Please use zipSerially instead.</i>
zipping :: IsStream t => ZipSerialM m a -> t m a

-- | Same as <a>zipAsyncly</a>.

-- | <i>Deprecated: Please use zipAsyncly instead.</i>
zippingAsync :: IsStream t => ZipAsyncM m a -> t m a

-- | Same as <a>wSerial</a>.

-- | <i>Deprecated: Please use <a>wSerial</a> instead.</i>
(<=>) :: IsStream t => t m a -> t m a -> t m a
infixr 5 <=>

-- | Same as <a>async</a>.

-- | <i>Deprecated: Please use <a>async</a> instead.</i>
(<|) :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a


-- | Time utilities for reactive programming.
module Streamly.Time

-- | Run an action forever periodically at the given frequency specified in
--   per second (Hz).
periodic :: Int -> IO () -> IO ()

-- | Run a computation on every clock tick, the clock runs at the specified
--   frequency. It allows running a computation at high frequency
--   efficiently by maintaining a local clock and adjusting it with the
--   provided base clock at longer intervals. The first argument is a base
--   clock returning some notion of time in microseconds. The second
--   argument is the frequency in per second (Hz). The third argument is
--   the action to run, the action is provided the local time as an
--   argument.
withClock :: IO Int -> Int -> (Int -> IO ()) -> IO ()


-- | Streamly is a general computing framework based on streaming IO. The
--   IO monad and pure lists are a special case of streamly. On one hand,
--   streamly extends the lists of pure values to lists of monadic actions,
--   on the other hand it extends the IO monad with concurrrent
--   non-determinism. In simple imperative terms we can say that streamly
--   extends the IO monad with <tt>for</tt> loops and nested <tt>for</tt>
--   loops with concurrency support. You can understand this analogy better
--   once you can go through this tutorial.
--   
--   Streaming in general enables writing modular, composable and scalable
--   applications with ease, and concurrency allows you to make them scale
--   and perform well. Streamly enables writing scalable concurrent
--   applications without being aware of threads or synchronization. No
--   explicit thread control is needed, where applicable the concurrency
--   rate is automatically controlled based on the demand by the consumer.
--   However, combinators can be used to fine tune the concurrency control.
--   
--   Streaming and concurrency together enable expressing reactive
--   applications conveniently. See the <tt>CirclingSquare</tt> example in
--   the examples directory for a simple SDL based FRP example. To
--   summarize, streamly provides a unified computing framework for
--   streaming, non-determinism and functional reactive programming in an
--   elegant and simple API that is a natural extension of pure lists to
--   monadic streams.
--   
--   In this tutorial we will go over the basic concepts and how to use the
--   library. See the last section for further reading resources.
module Streamly.Tutorial
