streamly-0.1.0: src/Streamly.hs
-- |
-- Module : Streamly
-- Copyright : (c) 2017 Harendra Kumar
--
-- License : BSD3
-- Maintainer : harendra.kumar@gmail.com
-- Stability : experimental
-- Portability : GHC
module Streamly
(
-- * Background
-- $background
-- * Overview
-- $overview
MonadAsync
, Streaming
-- * Product Style Composition
-- $product
, StreamT
, InterleavedT
, AsyncT
, ParallelT
-- * Zip Style Composition
-- $zipping
, ZipStream
, ZipAsync
-- * Sum Style Composition
-- $sum
, (<=>)
, (<|)
-- * Transformation
, async
-- * Stream Type Adapters
-- $adapters
, serially
, interleaving
, asyncly
, parallely
, zipping
, zippingAsync
, adapt
-- * Running Streams
, runStreaming
, runStreamT
, runInterleavedT
, runAsyncT
, runParallelT
, runZipStream
, runZipAsync
-- * Fold Utilities
-- $foldutils
, foldWith
, foldMapWith
, forEachWith
-- * Re-exports
, Monoid (..)
, Semigroup (..)
, Alternative (..)
, MonadPlus (..)
, MonadIO (..)
, MonadTrans (..)
)
where
import Streamly.Streams
import Data.Semigroup (Semigroup(..))
import Control.Applicative (Alternative(..))
import Control.Monad (MonadPlus(..))
import Control.Monad.IO.Class (MonadIO (..))
import Control.Monad.Trans.Class (MonadTrans (..))
-- $background
--
-- Streamly provides a monad transformer that extends the product style
-- composition of monads to streams of many elements of the same type; it is a
-- functional programming equivalent of nested loops from imperative
-- programming. Composing each element in one stream with each element in the
-- other stream generalizes the monadic product of single elements. You can
-- think of the IO monad as a special case of the more general @StreamT IO@
-- monad; with single element streams. List transformers and logic programming
-- monads also provide a similar product style composition of streams, however
-- streamly generalizes it with the time dimension; allowing streams to be
-- composed in an asynchronous and concurrent fashion in many different ways.
-- It also provides multiple alternative ways of composing streams e.g.
-- serial, interleaved or concurrent.
--
-- The seemingly simple addition of asynchronicity and concurrency to product
-- style streaming composition unifies a number of disparate abstractions into
-- one powerful and elegant abstraction. A wide variety of programming
-- problems can be solved elegantly with this abstraction. In particular, it
-- unifies three major programming domains namely non-deterministic (logic)
-- programming, concurrent programming and functional reactive programming. In
-- other words, you can do everything with this one abstraction that you could
-- with list transformers (e.g.
-- <https://hackage.haskell.org/package/list-t list-t>), logic programming
-- monads (e.g. <https://hackage.haskell.org/package/logict logict>),
-- streaming libraries (a lot of what
-- <https://hackage.haskell.org/package/conduit conduit> or
-- <https://hackage.haskell.org/package/pipes pipes> can do), concurrency
-- libraries (e.g. <https://hackage.haskell.org/package/async async>) and FRP
-- libraries (e.g. <https://hackage.haskell.org/package/Yampa Yampa> or
-- <https://hackage.haskell.org/package/reflex reflex>).
-- $overview
--
-- Streamly provides six distinct stream types i.e. 'StreamT', 'InterleavedT',
-- 'AsyncT' and 'ParallelT', 'ZipStream' and 'ZipAsync', each representing a
-- stream of elements. All these types have the same underlying representation
-- and can be adapted from one to another using type adaptor combinators
-- described later. Each of these types belongs to the 'Streaming' type class
-- which helps converting the specific type to and from the underlying generic
-- stream type.
--
-- The types 'StreamT', 'InterleavedT', 'AsyncT' and 'ParallelT' are 'Monad'
-- transformers with the monadic bind operation combining streams in a product
-- style in much the same way as a list monad or a list transformer i.e. each
-- element from one stream is combined with every element of the other stream.
-- However, the applicative and monadic composition of these types differ in
-- terms of the ordering and time sequence in which the elements from two
-- streams are combined. 'StreamT' and 'InterleavedT' compose streams serially
-- whereas 'AsyncT' and 'ParallelT' are their concurrent counterparts. See the
-- documentation of the respective types for more details.
--
-- The types 'ZipStream' and 'ZipAsync' provide 'Applicative' instances to zip
-- two streams together i.e. each element in one stream is combined with the
-- corresponding element in the other stream. 'ZipStream' generates the streams
-- being zipped serially whereas 'ZipAsync' produces both the elements being
-- zipped concurrently.
--
-- Two streams of the same type can be combined using a sum style composition
-- to generate a stream of the same type where the output stream would contain
-- all elements of both the streams. However, the sequence in which the
-- elements in the resulting stream are produced depends on the combining
-- operator. Four distinct sum style operators, '<>', '<=>', '<|' and '<|>'
-- combine two streams in different ways, each corresponding to the one of the
-- four ways of combining monadically. See the respective section below for
-- more details.
--
-- Concurrent composition types 'AsyncT', 'ParallelT', 'ZipAsync' and
-- concurrent composition operators '<|' and '<|>' require the underlying monad
-- of the streaming monad transformer to be 'MonadAsync'.
--
-- For more details please see the "Streamly.Tutorial" and "Streamly.Examples"
-- (the latter is available only when built with the 'examples' build flag).
-- A simple inline example here illustrating applicative, monad and alternative
-- compositions.
-- $product
--
-- Streams that compose serially or non-concurrently come in two flavors i.e.
-- 'StreamT' and 'InterleavedT'. Both of these serial flavors have
-- corresponding concurrent equivalents, those are 'AsyncT' and 'ParallelT'
-- respectively.
-- $zipping
--
-- 'ZipStream' and 'ZipAsync', provide 'Applicative' instances for zipping the
-- corresponding elements of two streams together. Note that these types are
-- not monads.
-- $sum
--
-- Just like product style composition there are four distinct ways to combine
-- streams in sum style each directly corresponding to one of the product style
-- composition.
--
-- The standard semigroup append '<>' operator appends two streams serially,
-- this style corresponds to the 'StreamT' style of monadic composition.
--
-- @
-- main = ('toList' . 'serially' $ (return 1 <> return 2) <> (return 3 <> return 4)) >>= print
-- @
-- @
-- [1,2,3,4]
-- @
--
-- The standard 'Alternative' operator '<|>' fairly interleaves two streams in
-- parallel, this operator corresponds to the 'ParallelT' style.
--
-- @
-- main = ('toList' . 'serially' $ (return 1 <> return 2) \<|\> (return 3 <> return 4)) >>= print
-- @
-- @
-- [1,3,2,4]
-- @
--
-- Unlike '<|', this operator cannot be used to fold infinite containers since
-- that might accumulate too many partially drained streams. To be clear, it
-- can combine infinite streams but not infinite number of streams.
--
-- Two additional sum style composition operators that streamly introduces are
-- described below.
-- $adapters
--
-- Code using streamly is usually written such that it is agnostic of any
-- specific streaming type. We use a type variable (polymorphic type) with the
-- 'Streaming' class constraint. Finally, when running the monad we can specify
-- the actual type that we want to use to interpret the code. However, in
-- certain cases we may want to use a specific type to force a certain type of
-- composition. These combinators can be used to convert the stream types from
-- one to another at no cost as all the types have the same underlying
-- representation.
--
-- If you see an @ambiguous type variable@ error then most likely it is because
-- you have not specified the stream type. You either need a type annotation or
-- one of the following combinators to specify what type of stream you mean.
--
-- This code:
--
-- @
-- main = ('toList' $ (return 1 <> return 2)) >>= print
-- @
--
-- will result in a type error like this:
--
-- @
-- Ambiguous type variable ‘t0’ arising from a use of ...
-- @
--
-- To fix the error just tell 'toList' what kind of stream are we feeding it:
--
-- @
-- main = ('toList' $ 'serially' $ (return 1 <> return 2)) >>= print
-- @
-- @
-- main = ('toList' $ (return 1 <> return 2 :: StreamT IO Int)) >>= print
-- @
--
-- Note that using the combinators is easier as you do not have to think about
-- the specific types, they are just inferred.
--
-- $foldutils
--
-- These are some convenience functions to fold any 'Foldable' container using
-- one of the sum composition operators to convert it into a streamly stream.