streaming 0.1.0.15 → 0.1.0.16
raw patch · 4 files changed
+142/−72 lines, 4 filesdep ~basedep ~transformers
Dependency ranges changed: base, transformers
Files
- Streaming.hs +5/−4
- Streaming/Internal.hs +77/−38
- Streaming/Prelude.hs +45/−17
- streaming.cabal +15/−13
Streaming.hs view
@@ -17,9 +17,11 @@ wrap, -- * Transforming streams+ decompose, maps, mapsM, distribute,+ eithers, -- * Inspecting a stream inspect,@@ -30,20 +32,19 @@ interleaves, -- * Eliminating a 'Stream'- intercalates,- concats, iterTM, iterT, destroy, mapsM_,- runEffect,+ run, -- * Splitting and joining 'Stream's splitsAt, takes, chunksOf, concats,-+ intercalates,+ -- * Base functor for streams of individual items Of (..), lazily,
Streaming/Internal.hs view
@@ -29,8 +29,10 @@ -- * Transforming streams , maps , mapsM + , decompose , mapsM_- , runEffect+ , eithers+ , run , distribute -- * Splitting streams@@ -59,12 +61,13 @@ import Data.Foldable ( Foldable(..) ) import Data.Traversable import Control.Monad.Morph-import Data.Monoid+import Data.Monoid (Monoid (..), (<>)) import Data.Functor.Identity import GHC.Exts ( build ) import Data.Data ( Data, Typeable ) import Prelude hiding (splitAt) import Data.Functor.Compose+import Data.Functor.Sum {- $stream The 'Stream' data type is equivalent to @FreeT@ and can represent any effectful@@ -123,14 +126,40 @@ Delay m -> Delay (liftM loop m) Step f -> Step (fmap loop f) {-# INLINABLE (>>) #-}- stream >>= f = loop stream where- loop stream0 = case stream0 of- Step f -> Step (fmap loop f)- Delay m -> Delay (liftM loop m)- Return r -> f r- {-# INLINABLE (>>=) #-} + (>>=) = _bind+ -- stream >>= f = + -- loop stream where+ -- loop stream0 = case stream0 of+ -- Step fstr -> Step (fmap loop fstr)+ -- Delay m -> Delay (liftM loop m)+ -- Return r -> f r+ -- {-# INLINABLE (>>=) #-} + fail = lift . fail+++_bind+ :: (Functor f, Monad m)+ => Stream f m r+ -> (r -> Stream f m s)+ -> Stream f m s+_bind p0 f = go p0 where+ go p = case p of+ Step fstr -> Step (fmap go fstr)+ Delay m -> Delay (m >>= \s -> return (go s))+ Return r -> f r++{-# RULES+ "_bind (Step fstr) f" forall fstr f .+ _bind (Step fstr) f = Step (fmap (\p -> _bind p f) fstr);+ "_bind (Delay m) f" forall m f .+ _bind (Delay m) f = Delay (m >>= \p -> return (_bind p f));+ "_bind (Return r) f" forall r f .+ _bind (Return r) f = f r;+ #-}+ + instance (Functor f, Monad m) => Applicative (Stream f m) where pure = Return {-# INLINE pure #-}@@ -283,7 +312,12 @@ Step f -> Step (phi (fmap loop f)) {-# INLINABLE maps #-} --- | Map layers of one functor to another with a transformation involving the base monad+{- | Map layers of one functor to another with a transformation involving the base monad+ @maps@ is more fundamental than @mapsM@, which is best understood as a convenience+ for effecting this frequent composition:++> mapsM phi = decompose . maps (Compose . phi)+-} mapsM :: (Monad m, Functor f) => (forall x . f x -> m (g x)) -> Stream f m r -> Stream g m r mapsM phi = loop where loop stream = case stream of @@ -292,22 +326,41 @@ Step f -> Delay (liftM Step (phi (fmap loop f))) {-# INLINABLE mapsM #-} +{-| Resort a succession of layers of the form @m (f x)@. Though @mapsM@ + is best understood as: +> mapsM phi = decompose . maps (Compose . phi)++ we could as well define @decompose@ by @mapsM@:++> decompose = mapsM getCompose++-}+decompose :: (Monad m, Functor f) => Stream (Compose m f) m r -> Stream f m r+decompose = loop where+ loop stream = case stream of + Return r -> Return r + Delay m -> Delay (liftM loop m)+ Step (Compose mstr) -> Delay $ do+ str <- mstr+ return (Step (fmap loop str))++ {-| Run the effects in a stream that merely layers effects. -}-runEffect :: Monad m => Stream m m r -> m r-runEffect = loop where+run :: Monad m => Stream m m r -> m r+run = loop where loop stream = case stream of Return r -> return r Delay m -> m >>= loop Step mrest -> mrest >>= loop-{-# INLINABLE runEffect #-}+{-# INLINABLE run #-} {-| Map each layer to an effect in the base monad, and run them all. -} mapsM_ :: (Functor f, Monad m) => (forall x . f x -> m x) -> Stream f m r -> m r-mapsM_ f str = runEffect (maps f str)+mapsM_ f str = run (maps f str) {-# INLINABLE mapsM_ #-} @@ -424,30 +477,7 @@ Step fs -> Step $ Step $ fmap (fmap loop . splitsAt (n0-1)) 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 "Current state is: " >> print s-> lift $ put (s + n :: Int)-> loop s-->>> S.print $ S.take 4 $ S.drop 4 $ debugFibs-Current state is: 1-Current state is: 2-Current state is: 3-Current state is: 5-5-Current state is: 8-8-Current state is: 13-13-Current state is: 21-21-+{- | Make it possible to \'run\' the underlying transformed monad. -} distribute :: (Monad m, Functor f, MonadTrans t, MFunctor t, Monad (t (Stream f m))) => Stream f (t m) r -> t (Stream f m) r@@ -591,7 +621,16 @@ {-# INLINE interleaves #-} -+eithers :: (Monad m, Applicative h) => + (forall x . f x -> h x) -> (forall x . g x -> h x) -> Stream (Sum f g) m r -> Stream h m r+eithers f g = loop where+ loop str = case str of + Return r -> Return r+ Delay m -> Delay (liftM loop m)+ Step str' -> case str' of + InL s -> Step (fmap loop (f s))+ InR t -> Step (fmap loop (g t))+
Streaming/Prelude.hs view
@@ -2,15 +2,7 @@ simplify and optimize the conception of Producer manipulation contained in Pipes.Group, Pipes.Parse and the like. This is very simple and unmysterious; it is independent of piping and conduiting, and can be used with any - rational \"streaming IO\" system.-- Some interoperation incantations would be e.g. --> 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.reread IOStreams.read :: InputStream a -> Stream (Of a) IO ()-> IOStreams.unfoldM Streaming.uncons :: Stream (Of a) IO () -> IO (InputStream a)-> Conduit.unfoldM Streaming.uncons :: Stream (Of a) m () -> Source m a+ rational \"streaming IO\" system. Import qualified thus: @@ -150,6 +142,9 @@ import Data.Data ( Data, Typeable ) import Data.Functor.Identity import Control.Monad.Trans+import Control.Applicative (Applicative (..))+import Data.Functor (Functor (..), (<$))+ import qualified Prelude as Prelude import Data.Foldable (Foldable) import Data.Traversable (Traversable)@@ -165,14 +160,47 @@ import qualified System.IO as IO import Foreign.C.Error (Errno(Errno), ePIPE) import Control.Exception (throwIO, try)-+import Data.Monoid (Monoid (..)) -- | A left-strict pair; the base functor for streams of individual elements. data Of a b = !a :> b- deriving (Data, Eq, Foldable, Functor, Ord,+ deriving (Data, Eq, Foldable, Ord, Read, Show, Traversable, Typeable)-infixr 4 :>+infixr 5 :> +instance (Monoid a, Monoid b) => Monoid (Of a b) where+ mempty = mempty :> mempty+ {-#INLINE mempty #-}+ mappend (m :> w) (m' :> w') = mappend m m' :> mappend w w'+ {-#INLINE mappend #-}+ mconcat = foldr mappend mempty+ {-#INLINE mconcat #-}++instance Functor (Of a) where+ fmap f (a :> x) = a :> f x+ {-#INLINE fmap #-}+ a <$ (b :> x) = b :> a+ {-#INLINE (<$) #-}++instance Monoid a => Applicative (Of a) where+ pure x = mempty :> x+ {-#INLINE pure #-}+ m :> f <*> m' :> x = mappend m m' :> f x+ {-#INLINE (<*>) #-}+ m :> x *> m' :> y = mappend m m' :> y+ {-#INLINE (*>) #-}+ m :> x <* m' :> y = mappend m m' :> x + {-#INLINE (<*) #-}++instance Monoid a => Monad (Of a) where+ return x = mempty :> x+ {-#INLINE return #-}+ m :> x >> m' :> y = mappend m m' :> y+ {-#INLINE (>>) #-}+ m :> x >>= f = let m' :> y = f x in mappend m m' :> y+ {-#INLINE (>>=) #-}++ lazily :: Of a b -> (a,b) lazily = \(a:>b) -> (a,b) {-# INLINE lazily #-}@@ -186,6 +214,8 @@ snd' :: Of a b -> b snd' (a :> b) = b++ {-| Break a sequence when a element falls under a predicate, keeping the rest of the stream as the return value. @@ -327,7 +357,7 @@ -- | Ignore the first n elements of a stream, but carry out the actions drop :: (Monad m) => Int -> Stream (Of a) m r -> Stream (Of a) m r drop = loop where- loop n stream + loop !n stream | n <= 0 = stream | otherwise = case stream of Return r -> Return r@@ -363,12 +393,10 @@ {- | Stream the elements of a foldable container. ->>> S.print $ S.map (*100) $ each [1..3] >> yield 4-0+>>> S.print $ S.map (*100) $ each [1..3] 100 200 300-400 >>> S.print $ S.map (*100) $ each [1..3] >> lift readLn >>= yield 100@@ -783,7 +811,7 @@ -} product' :: (Monad m, Num a) => Stream (Of a) m r -> m (Of a r) product' = fold' (*) 1 id-{-# INLINAE product' #-}+{-# INLINE product' #-} -- --------------- -- read
streaming.cabal view
@@ -1,29 +1,29 @@ name: streaming-version: 0.1.0.15+version: 0.1.0.16 cabal-version: >=1.10 build-type: Simple synopsis: a free monad transformer optimized for streaming applications -description: @Stream@ can be used wherever @FreeT@ is used. The compiler's+description: @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@. . - See the examples in @Streaming.Prelude@ for a sense of how - simple the library is to use and think about. - That module is focused on employment with such base functors - (readings of the @f@ in @Stream f m r@) that express - different forms of effectful sequences. Some of these appear - elsewhere under titles like+ @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 .- and the like. @Streaming.Prelude@ closely follows @Pipes.Prelude@, but cleverly /omits the pipes/:+ @Streaming.Prelude@ closely follows @Pipes.Prelude@, but cleverly /omits the pipes/: .- > ghci> S.stdoutLn $ S.take 2 S.stdinLn > let's<Enter> > let's@@ -40,7 +40,7 @@ > 49 . Somehow, we didn't even need a four-character operator for that, nor advice- about best practices; just ordinary Haskell common sense. + about best practices! - just ordinary Haskell common sense. . The simplest form of interoperation with <http://hackage.haskell.org/package/pipes pipes>@@ -49,7 +49,9 @@ > 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 + (@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: .@@ -102,7 +104,7 @@ DeriveFunctor, DeriveTraversable, UndecidableInstances - build-depends: base >=4.6 && <4.9+ build-depends: base >=4.6 && <5 , mtl >=2.1 && <2.3 , mmorph >=1.0 && <1.2 , transformers >=0.3 && <0.5