streaming 0.1.0.1 → 0.1.0.3
raw patch · 4 files changed
+153/−30 lines, 4 files
Files
- Streaming.hs +12/−2
- Streaming/Internal.hs +61/−5
- Streaming/Prelude.hs +54/−16
- streaming.cabal +26/−7
Streaming.hs view
@@ -13,6 +13,7 @@ maps, maps', mapsM,+ distribute, -- * Inspecting a stream inspect,@@ -65,8 +66,17 @@ > Stream (Of a) m (Stream (Of a) m r) -- the effectful splitting of a producer > -- i.e. an effectful ([a],[a]) or rather ([a],([a],r)) > Stream (Stream (Of a) m) m r -- successive, segmentation of a producer- -- i.e. [[a]], or ([a],([a],([a]... r)))- and so on. But of course any functor can be used.+> -- i.e. [[a]], or ([a],([a],([a]... r)))++ and so on. But of course any functor can be used. So, for example, ++> Stream ((->) input) m result++ is a simple @Consumer input m result@ or @Parser input m result@ type. And so on.+ See e.g. http://www.haskellforall.com/2012/07/purify-code-using-free-monads.html ,+ http://www.haskellforall.com/2012/07/free-monad-transformers.html and similar+ literature.+ To avoid breaking reasoning principles, the constructors should not be used directly. A pattern-match should go by way of 'inspect'
Streaming/Internal.hs view
@@ -15,6 +15,7 @@ , intercalates , iterT , iterTM + -- * Inspecting a stream step by step , inspect @@ -22,6 +23,7 @@ -- * Transforming streams , maps , mapsM + , distribute -- * Splitting streams , chunksOf @@ -128,7 +130,7 @@ liftIO = Delay . liftM Return . liftIO {-# INLINE liftIO #-} --- | Map a stream to its church encoding; compare list 'foldr'+-- | Map a stream to its church encoding; compare @Data.List.foldr@ destroy :: (Functor f, Monad m) => Stream f m r -> (f b -> b) -> (m b -> b) -> (r -> b) -> b@@ -139,7 +141,7 @@ Step fs -> construct (fmap loop fs) {-# INLINABLE destroy #-} --- | Reflect a church-encoded stream; cp. GHC.Exts.build+-- | Reflect a church-encoded stream; cp. @GHC.Exts.build@ construct :: (forall b . (f b -> b) -> (m b -> b) -> (r -> b) -> b) -> Stream f m r construct = \phi -> phi Step Delay Return@@ -162,7 +164,8 @@ Step fs -> return (Right fs) {-# INLINABLE inspect #-} -{-| Build a @Stream@ by unfolding steps starting from a seed. +{-| Build a @Stream@ by unfolding steps starting from a seed. See also+ the specialized 'Streaming.Prelude.unfoldr' in the prelude. > unfold inspect = id -- modulo the quotient we work with > unfold Pipes.next :: Monad m => Producer a m r -> Stream ((,) a) m r@@ -201,8 +204,10 @@ {-# INLINABLE mapsM #-} -+{-| Interpolate a layer at each segment. This specializes to e.g. +> intercalates :: (Monad m, Functor f) => Stream f m () -> Stream (Stream f m) m r -> Stream f m r+-} intercalates :: (Monad m, Monad (t m), MonadTrans t) => t m a -> Stream (t m) m b -> t m b intercalates sep = go0@@ -222,6 +227,10 @@ go1 f' {-# INLINABLE intercalates #-} +{-| Specialized fold++> iterTM alg stream = destroy stream alg (join . lift) return+-} iterTM :: (Functor f, Monad m, MonadTrans t, Monad (t m)) =>@@ -229,18 +238,31 @@ iterTM out stream = destroy stream out (join . lift) return {-# INLINE iterTM #-} +{-| Specialized fold++> iterT alg stream = destroy stream alg join return+-} iterT :: (Functor f, Monad m) => (f (m a) -> m a) -> Stream f m a -> m a iterT out stream = destroy stream out join return {-# INLINE iterT #-} +{-| This specializes to the more transparent case:++> concats :: (Monad m, Functor f) => Stream (Stream f m) m r -> Stream f m r++ Thus dissolving the segmentation into @Stream f m@ layers.++> concats stream = destroy stream join (join . lift) return+-} concats :: (MonadTrans t, Monad (t m), Monad m) => Stream (t m) m a -> t m a concats stream = destroy stream join (join . lift) return {-# INLINE concats #-} -+-- | Split a succession of layers after some number, returning a streaming or+-- effectful pair. split :: (Monad m, Functor f) => Int -> Stream f m r -> Stream f m (Stream f m r) split = loop where loop !n stream @@ -253,6 +275,7 @@ _ -> Step (fmap (loop (n-1)) fs) {-# INLINABLE split #-} +-- | Break a stream into substreams each with n functorial layers. chunksOf :: (Monad m, Functor f) => Int -> Stream f m r -> Stream (Stream f m) m r chunksOf n0 = loop where loop stream = case stream of@@ -260,3 +283,36 @@ Delay m -> Delay (liftM loop m) Step fs -> Step $ Step $ fmap (fmap loop . split n0) fs {-# INLINABLE chunksOf #-} ++{- | Make it possible to \'run\' the underlying transformed monad. A simple+ minded example might be: ++> debugFibs = flip runStateT 1 $ distribute $ loop 1 where+> loop n = do+> S.yield n+> s <- lift get +> liftIO $ putStr "state is: " >> print s+> lift $ put (s + n :: Int)+> loop s++>>> S.print $ S.take 4 $ S.drop 4 $ debugFibs+state is: 1+state is: 2+state is: 3+state is: 5+5+state is: 8+8+state is: 13+13+state is: 21+21++-}+distribute :: (Monad m, Functor f, MonadTrans t, MFunctor t, Monad (t (Stream f m)))+ => Stream f (t m) r -> t (Stream f m) r+distribute = loop where+ loop stream = case stream of + Return r -> lift $ Return r+ Delay tmstr -> hoist lift tmstr >>= distribute+ Step fstr -> join $ lift (Step (fmap (Return . distribute) fstr))
Streaming/Prelude.hs view
@@ -149,7 +149,13 @@ {-| Apply an action to all values flowing downstream -> let debug str = chain print str+>>> let debug str = chain print str+>>> S.product (debug (S.each [2..4])) >>= print+2+3+4+24+ -} chain :: Monad m => (a -> m ()) -> Stream (Of a) m r -> Stream (Of a) m r chain f str = for str $ \a -> do@@ -157,7 +163,14 @@ yield a {-# INLINE chain #-} +{-| Make a stream of traversable containers into a stream of their separate elements +>>> Streaming.print $ concat (each ["hi","ho"])+'h'+'i'+'h'+'o'+-} concat :: (Monad m, Foldable f) => Stream (Of (f a)) m r -> Stream (Of a) m r concat str = for str each@@ -209,7 +222,13 @@ -- each -- --------------- --- | Stream the elements of a foldable container.+{- | Stream the elements of a foldable container.++>>> S.print $ S.each [1..3]+1+2+3+-} each :: (Monad m, Foldable.Foldable f) => f a -> Stream (Of a) m () each = Foldable.foldr (\a p -> Step (a :> p)) (Return ()) {-# INLINE each #-}@@ -351,8 +370,8 @@ See also the more general 'iterTM' in the 'Streaming' module and the still more general 'destroy' -foldrT (\a p -> Pipes.yield a >> p) :: Monad m => Stream (Of a) m r -> Producer a m r-foldrT (\a p -> Conduit.yield a >> p) :: Monad m => Stream (Of a) m r -> Conduit a m r+> foldrT (\a p -> Pipes.yield a >> p) :: Monad m => Stream (Of a) m r -> Producer a m r+> foldrT (\a p -> Conduit.yield a >> p) :: Monad m => Stream (Of a) m r -> Conduit a m r -} @@ -493,12 +512,20 @@ There is no reason to prefer @inspect@ since, if the @Right@ case is exposed, the first element in the pair will have been evaluated to whnf. -next :: Monad m => Stream (Of a) m r -> m (Either r (a, Stream (Of a) m r))-inspect :: Monad m => Stream (Of a) m r -> m (Either r (Of a (Stream (Of a) m r)))+> next :: Monad m => Stream (Of a) m r -> m (Either r (a, Stream (Of a) m r))+> inspect :: Monad m => Stream (Of a) m r -> m (Either r (Of a (Stream (Of a) m r))) -IOStreams.unfoldM (liftM (either (const Nothing) Just) . next) :: Stream (Of a) IO b -> IO (InputStream a)-Conduit.unfoldM (liftM (either (const Nothing) Just) . next) :: Stream (Of a) m r -> Source a m r+ Interoperate with @pipes@ producers thus: +> Pipes.unfoldr Stream.next :: Stream (Of a) m r -> Producer a m r+> Stream.unfoldr Pipes.next :: Producer a m r -> Stream (Of a) m r + + Similarly: ++> IOStreams.unfoldM (liftM (either (const Nothing) Just) . next) :: Stream (Of a) IO b -> IO (InputStream a)+> Conduit.unfoldM (liftM (either (const Nothing) Just) . next) :: Stream (Of a) m r -> Source a m r++ But see 'uncons' -} next :: Monad m => Stream (Of a) m r -> m (Either r (a, Stream (Of a) m r)) next = loop where@@ -512,8 +539,8 @@ {-| Inspect the first item in a stream of elements, without a return value. Useful for unfolding into another streaming type. -IOStreams.unfoldM uncons :: Stream (Of a) IO b -> IO (InputStream a)-Conduit.unfoldM uncons :: Stream (Of o) m r -> Conduit.Source m o+> IOStreams.unfoldM uncons :: Stream (Of a) IO b -> IO (InputStream a)+> Conduit.unfoldM uncons :: Stream (Of o) m r -> Conduit.Source m o -} uncons :: Monad m => Stream (Of a) m () -> m (Maybe (a, Stream (Of a) m ()))@@ -568,13 +595,14 @@ -- replicate -- --------------- +-- | Repeat an element several times replicate :: Monad m => Int -> a -> Stream (Of a) m () replicate n a = loop n where loop 0 = Return () loop m = Step (a :> loop (m-1)) {-# INLINEABLE replicate #-} --- | Repeat an action, streaming the results.+-- | Repeat an action several times, streaming the results. replicateM :: Monad m => Int -> m a -> Stream (Of a) m () replicateM n ma = loop n where loop 0 = Return ()@@ -587,6 +615,13 @@ {-| Strict left scan, streaming, e.g. successive partial results. > Control.Foldl.purely scan :: Monad m => Fold a b -> Stream (Of a) m r -> Stream (Of b) m r++>>> Streaming.print $ Foldl.purely Streaming.scan Foldl.list $ each [3..5]+[]+[3]+[3,4]+[3,4,5]+ -} scan :: Monad m => (x -> a -> x) -> x -> (x -> b) -> Stream (Of a) m r -> Stream (Of b) m r scan step begin done = loop begin@@ -625,10 +660,13 @@ -- sequence -- --------------- --- | Like the 'Data.List.sequence' but streaming. The result type is a--- stream of a\'s, but is not accumulated; the effects of the elements--- of the original stream are interleaved in the resulting stream.+{-| Like the 'Data.List.sequence' but streaming. The result type is a+ stream of a\'s, /but is not accumulated/; the effects of the elements+ of the original stream are interleaved in the resulting stream. Compare: +> sequence :: Monad m => [m a] -> m [a]+> sequence :: Monad m => Stream (Of (m a)) m r -> Stream (Of a) m r+-} sequence :: Monad m => Stream (Of (m a)) m r -> Stream (Of a) m r sequence = loop where loop stream = case stream of@@ -751,8 +789,8 @@ more general 'unfold' would require dealing with the left-strict pair we are using. -unfoldr Pipes.next :: Monad m => Producer a m r -> Stream (Of a) m r-unfold (curry (:>) . Pipes.next) :: Monad m => Producer a m r -> Stream (Of a) m r+> unfoldr Pipes.next :: Monad m => Producer a m r -> Stream (Of a) m r+> unfold (curry (:>) . Pipes.next) :: Monad m => Producer a m r -> Stream (Of a) m r -} unfoldr :: Monad m
streaming.cabal view
@@ -1,12 +1,32 @@ name: streaming-version: 0.1.0.1+version: 0.1.0.3 cabal-version: >=1.10 build-type: Simple-synopsis: A general free monad transformer optimized for streaming applications.-description: Stream is an optimized variant of FreeT.- It can be used wherever FreeT is used, but is focused- on employment with functors like '((,) a)' which generate- effectful sequences or \"producers\"+synopsis: A general free monad transformer + optimized for streaming applications.+ +description: `Stream` can be used wherever `FreeT` is used. The compiler+ is better able to optimize operations written in+ terms of `Stream`.+ .+ An associated prelude of functions, closely following + @Pipes.Prelude@ is focused on on employment with a base + functor like @((,) a)@ (here called @Of a@) which generates+ effectful sequences or producers - @Pipes.Producer@, + @Conduit.Source@, @IOStreams.InputStream@, @IOStreams.Generator@+ and the like.+ .+ Interoperation with `pipes` is accomplished with this isomorphism:+ . + > Pipes.unfoldr Streaming.next :: Stream (Of a) m r -> Producer a m r+ > Stream.unfoldr Pipes.next :: Producer a m r -> Stream (Of a) m r+ .+ Exit to `conduit` and `iostreams` is thus:+ .+ > Conduit.unfoldM Streaming.uncons :: Stream (Of a) m () -> Source m a+ > IOStreams.unfoldM Streaming.uncons :: Stream (Of a) IO () -> InputStream a+ + license: BSD3 license-file: LICENSE author: michaelt@@ -39,7 +59,6 @@ , ghc-prim default-language: Haskell2010- ghc-options: -O2