streaming-0.1.4.1: streaming.cabal
name: streaming
version: 0.1.4.1
cabal-version: >=1.10
build-type: Simple
synopsis: an elementary streaming prelude and general stream type.
description: @Streaming.Prelude@ exports an elementary streaming prelude focused on
a simple \"source\" or \"producer\" type, namely @Stream (Of a) m r@.
This is a sort of effectful version of @([a],r)@ in which monadic action
is interleaved between successive elements.
The main module, @Streaming@, exports a much more general type,
@Stream f m r@, which can be used to stream successive distinct
steps characterized by /any/
functor @f@, though we are here interested only in a limited range of
cases.
.
The streaming-IO libraries have various devices for dealing
with effectful variants of @[a]@ or @([a],r)@. But it is only with
the general type @Stream f m r@, or some equivalent,
that one can envisage (for example) the connected streaming of their
sorts of stream -- as one makes lists of lists in the Haskell
@Prelude@ and @Data.List@. One needs some such type if we are
to express properly streaming equivalents of e.g.
.
> group :: Ord a => [a] -> [[a]]
> chunksOf :: Int -> [a] -> [[a]]
> lines :: [Char] -> [[Char]] -- but similarly with bytestring, etc.
.
to mention a few obviously desirable operations. But once one grasps
the iterable stream concept needed to express those functions - to wit,
@Stream f m r@ or some equivalent - then one will also see that,
with it, one is already in possession of a complete
elementary streaming library - since one possesses @Stream ((,) a) m r@
or equivalently @Stream (Of a) m r@. This
is the type of a \'generator\' or \'producer\' or whatever
you call an effectful stream of items.
The present @Streaming.Prelude@ is thus the simplest streaming
library that can replicate anything like the API of the
@Prelude@ and @Data.List@.
.
The emphasis of the library is on interoperation; for
the rest its advantages are: extreme simplicity and re-use of
intuitions the user has gathered from mastery of @Prelude@ and
@Data.List@. The two conceptual pre-requisites are some
comprehension of monad transformers and some familiarity
with \'rank 2 types\'.
.
See the
<https://hackage.haskell.org/package/streaming#readme readme>
below for an explanation, including the examples linked there.
Elementary usage can be divined from the ghci examples in
@Streaming.Prelude@ and perhaps from this rough beginning of a
<https://github.com/michaelt/streaming-tutorial/blob/master/tutorial.md tutorial>.
Note also the
<https://hackage.haskell.org/package/streaming-bytestring streaming bytestring>
and
<https://hackage.haskell.org/package/streaming-utils streaming utils>
packages. Questions about usage can be put
raised on StackOverflow with the tag @[haskell-streaming]@,
or as an issue on Github, or on the
<https://groups.google.com/forum/#!forum/haskell-pipes pipes list>
(the package understands itself as part of the pipes \'ecosystem\'.)
.
The simplest form of interoperation with
<http://hackage.haskell.org/package/pipes pipes>
is accomplished with this isomorphism:
.
> Pipes.unfoldr Streaming.next :: Stream (Of a) m r -> Producer a m r
> Streaming.unfoldr Pipes.next :: Producer a m r -> Stream (Of a) m r
.
Interoperation with
<http://hackage.haskell.org/package/io-streams io-streams>
is thus:
.
> Streaming.reread IOStreams.read :: InputStream a -> Stream (Of a) IO ()
> IOStreams.unfoldM Streaming.uncons :: Stream (Of a) IO () -> IO (InputStream a)
.
With
<http://hackage.haskell.org/package/conduit conduit>
one might use, e.g.:
.
> Conduit.unfoldM Streaming.uncons :: Stream (Of a) m () -> Source m a
> Streaming.mapM_ Conduit.yield . hoist lift :: Stream (Of o) m r -> ConduitM i o m r
> ($$ Conduit.mapM_ Streaming.yield) . hoist lift :: Source m a -> Stream (Of a) m ()
.
These conversions should never be more expensive than a single @>->@ or @=$=@.
.
Here is a simple example (conceptually it is a bit advanced, maybe)
that runs a single underlying stream with several
streaming-io libraries at once, superimposing their effects
without any accumulation:
.
> module Main (main) where
> import Streaming
> import Pipes
> import Data.Conduit
> import qualified Streaming.Prelude as S
> import qualified Data.Conduit.List as CL
> import qualified Pipes.Prelude as P
> import qualified System.IO.Streams as IOS
> import Data.ByteString.Char8 (pack)
> import Data.Function ((&))
>
> mkConduit = CL.unfoldM S.uncons
> mkPipe = P.unfoldr S.next
> mkIOStream = IOS.unfoldM S.uncons
>
> main = iostreamed where
> urstream = S.take 3 S.readLn :: Stream (Of Int) IO ()
> streamed = S.copy urstream & S.map (\n -> "streaming says: " ++ show n)
> & S.stdoutLn
> piped = runEffect $
> mkPipe (S.copy streamed) >-> P.map (\n -> "pipes says: " ++ show n)
> >-> P.stdoutLn
> conduited =
> mkConduit (S.copy piped) $$ CL.map (\n -> "conduit says: " ++ show n)
> =$ CL.mapM_ (liftIO . putStrLn)
> iostreamed = do
> str0 <- mkIOStream conduited
> str1 <- IOS.map (\n -> pack $ "io-streams says: " ++ show n ++ "\n") str0
> IOS.supply str1 IOS.stdout
.
This program successively parses three @Int@s from standard input,
and /simulaneously/ passes them to (here trivial) stream-consuming
processes from four different libraries, using the @copy@ function from
@Streaming.Prelude@. I mark my own input with @/<Enter/>@ below:
.
> >>> main
> 1 <Enter>
> streaming says: 1
> pipes says: 1
> conduit says: 1
> io-streams says: 1
> 2 <Enter>
> streaming says: 2
> pipes says: 2
> conduit says: 2
> io-streams says: 2
> 3 <Enter>
> streaming says: 3
> pipes says: 3
> conduit says: 3
> io-streams says: 3
> >>>
.
Of course, I could as well have passed the stream to several
independent conduits; and I might have derived the original
stream from a conduit @Source@ or pipes @Producer@ etc., using
one of the \'conversion\' functions above. Further
points of comparison with the going streaming-IO libraries
are discussed in the
<https://hackage.haskell.org/package/streaming#readme readme>
below.
.
Here are the results of some
<https://gist.github.com/michaelt/f19bef01423b17f29ffd microbenchmarks>
based on the
<https://github.com/ekmett/machines/blob/master/benchmarks/Benchmarks.hs benchmarks>
included in the machines package:
.
<<http://i.imgur.com/sSG5MvH.png>>
.
Because these are microbenchmarks for individual functions,
they represent a sort of \"worst case\"; many other factors can influence
the speed of a complex program.
.
license: BSD3
license-file: LICENSE
author: michaelt
maintainer: what_is_it_to_do_anything@yahoo.com
stability: Experimental
homepage: https://github.com/michaelt/streaming
bug-reports: https://github.com/michaelt/streaming/issues
category: Data, Pipes, Streaming
extra-source-files: README.md
source-repository head
type: git
location: https://github.com/michaelt/streaming
library
exposed-modules: Streaming,
Streaming.Prelude,
Streaming.Internal
-- other-modules:
other-extensions: RankNTypes, CPP,
StandaloneDeriving, FlexibleContexts,
DeriveDataTypeable, DeriveFoldable,
DeriveFunctor, DeriveTraversable,
UndecidableInstances
build-depends: base >=4.6 && <5
, mtl >=2.1 && <2.3
, mmorph >=1.0 && <1.2
, transformers >=0.4 && <0.5.2
, transformers-base < 0.5
, resourcet > 1.1.0 && < 1.2
, exceptions > 0.5 && < 0.9
, time
, ghc-prim
default-language: Haskell2010