streaming-0.1.0.17: streaming.cabal
name: streaming
version: 0.1.0.17
cabal-version: >=1.10
build-type: Simple
synopsis: a free monad transformer optimized for streaming applications
description: __The free stream on a streamable functor__
.
@Stream@ can be used wherever
<https://hackage.haskell.org/package/free-4.12.1/docs/Control-Monad-Trans-Free.html FreeT>
is used. The compiler's
standard range of optimizations work better for operations
written in terms of `Stream`. @FreeT f m r@ / @Stream f m r@
is of course extremely general, and many functor-general combinators
are exported by the general module @Streaming@.
.
@Streaming.Prelude@ is focused on elementary /streaming/ applications.
Here the free iteration of the \'base\' functors
(readings of the @f@ in @Stream f m r@) express
forms of effectful sequence or succession. Some of types in question
appear in the streaming IO libraries under titles like
.
> pipes: Producer a m r, Producer a m (Producer a m r), FreeT (Producer a m) m r
> io-streams: InputStream a, Generator a r
> conduit: Source m a, ConduitM () o m r
.
@Streaming.Prelude@ closely follows @Pipes.Prelude@, but cleverly /omits the pipes/:
.
> ghci> S.stdoutLn $ S.take 2 S.stdinLn
> let's<Enter>
> let's
> stream<Enter>
> stream
.
And here we do a little /connect and resume/, as the streaming-io experts call it:
.
> ghci> rest <- S.print $ S.splitAt 3 $ S.each [1..10]
> 1
> 2
> 3
> ghci> S.sum rest
> 49
.
Somehow, we didn't even need a four-character operator for that, nor advice
about best practices! - just ordinary Haskell common sense.
.
__Didn't I hear that free monads are horrible?__
.
If @Stream f m r@ is instantiated to @Stream f Identity m r@ then we have
the standard /free monad construction/. This is subject to certain familiar
objections from an efficiency perspective; efforts have been made to
substitute exotic cps-ed implementations and so forth.
.
In fact, the standard fast talk about /retraversing binds/ and /quadratic explosions/ and
/costly appends/, and so on become transparent nonsense with @Stream f m r@
in its streaming use. The insight needed to see this is basically nil: Where @m@ is read as
@IO@, or some transformed @IO@, then the dreaded /retraversing of the binds/
in a stream expression would involve repeating all the past actions. Don't worry, to get e.g. the
second chunk of bytes from a handle, you won't need to start over and get the first
one again! The first chunk has vanished into an unrepeatable past.
.
All of the difficulties a streaming library is attempting to avoid
are concentrated in the deep irrationality of
.
> sequence :: (Monad m, Traversable t) => t (m a) -> m (t a)
.
In the streaming context, this becomes
.
> sequence :: Monad m, Functor f => Stream f m r -> Stream f m r
> sequence = id
.
It is of course easy enough to define
.
> accumulate :: Monad m, Functor f => Stream f m r -> m (Stream f Identity r)
.
or @reifyBinds@, as you might call it. Small experience will
teach the user how to avoid or control the sort of accumulation
characteristic of @sequence@ in its various guises e.g. @mapM f = sequence . map f@ and
@traverse f = sequence . fmap f@ and @replicateM n = sequence . replicate n@.
See for example the types of
.
> Control.Monad.replicateM :: Int -> m a -> m [a]
> Streaming.Prelude.replicateM :: Int -> m a -> Stream (Of a) m ()
.
If you want to tempt fate and replicate the irrationality of @Control.Monad.replicateM@,
then sure, you can write the hermaphroditic, chimerical
.
> accumulate . Streaming.Prelude.replicateM :: Int -> m a -> m (Stream (Of a) Identity ())
.
but once you know how to operate with a stream directly you will see less and less point
in what is called /extracting the (structured) value from IO/. With @sequence@ and @traverse@,
we accumulate a structure holding pure values from a structure holding monadic
values. Why bother when you have intrinsically monadic structures? @Stream f m r@
gives you an immense body of such structures and a simple discipline for working with them.
.
__Interoperation with the streaming-io libraries__
.
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
.
(@streaming@ can be mixed with @pipes@ wherever @pipes@
itself employs @Control.Monad.Trans.Free@; speedups are frequently
appreciable.) 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)
.
A simple exit to <http://hackage.haskell.org/package/conduit conduit> would be, e.g.:
.
> Conduit.unfoldM Streaming.uncons :: Stream (Of a) m () -> Source m a
.
These conversions should never be more expensive than a single @>->@ or @=$=@.
.
At a much more general level, we also of course have interoperation with
<http://hackage.haskell.org/package/free free>:
.
> Free.iterTM Stream.wrap :: FreeT f m a -> Stream f m a
> Stream.iterTM Free.wrap :: Stream f m a -> FreeT f m a
.
__Examples__
.
For some simple ghci examples, see the commentary throughout the Prelude module.
For slightly more advanced usage see the commentary in the haddocks of <https://hackage.haskell.org/package/streaming-bytestring streaming-bytestring>
and e.g.
<https://gist.github.com/michaelt/6c6843e6dd8030e95d58 these replicas> of shell-like programs from
the io-streams tutorial.
Here's a simple <https://gist.github.com/michaelt/2dcea1ba32562c091357 streaming GET request> with
intrinsically streaming byte streams.
.
__Problems__
.
Questions about this library can be put as issues through the github site or
on the <https://groups.google.com/forum/#!forum/haskell-pipes pipes mailing list>.
(This library understands itself as part of the pipes "ecosystem.")
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
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
default-language: Haskell2010