streaming 0.1.0.5 → 0.1.0.6
raw patch · 3 files changed
+106/−56 lines, 3 files
Files
- Streaming.hs +1/−2
- Streaming/Prelude.hs +87/−36
- streaming.cabal +18/−18
Streaming.hs view
@@ -14,7 +14,6 @@ -- * Transforming streams maps,- maps', mapsM, distribute, @@ -33,7 +32,7 @@ chunksOf, concats, - -- * Useful functors+ -- * Base functor for streams of individual items Of (..), lazily, strictly,
Streaming/Prelude.hs view
@@ -58,7 +58,6 @@ -- $pipes , map , mapM- , maps' , maps , sequence , mapFoldable@@ -355,13 +354,39 @@ -- --------------- {- $folds- Use these to fold the elements of a 'Stream'. The general folds 'fold', fold\'',- 'foldM' and 'foldM\'' are arranged for use with 'Control.Foldl' All functions marked- with a final '\'' (e.g. 'fold\'', 'sum\') carry the stream's return value -- or, in- the case of 'maps\'' are tailored to take such an operation as argument.+ Use these to fold the elements of a 'Stream'. -> maps' sum' :: (Monad m, Num n) => Stream (Stream (Of n)) m r -> Stream (Of n) m r-> maps' (fold' mappend mempty id) :: :: (Monad m, Num n) => Stream (Stream (Of n)) m r -> Stream (Of n) m r+>>> S.fold (+) 0 id $ S.each [1..0]+50++ The general folds 'fold', fold\'', 'foldM' and 'foldM\'' are arranged + for use with 'Control.Foldl'++>>> L.purely fold L.sum $ each [1..10]+55+>>> L.purely fold (liftA3 (,,) L.sum L.product L.list) $ each [1..10]+(55,3628800,[1,2,3,4,5,6,7,8,9,10])++ All functions marked with a single quote + (e.g. @fold'@, @sum'@ carry the stream's return value in a left-strict pair.+ These are convenient for @mapsM@-ing over a @Stream (Stream (Of a) m) m r@, + which is to be compared with @[[a]]@. Specializing, we have e.g.++> mapsM sum' :: (Monad m, Num n) => Stream (Stream (Of Int)) IO () -> Stream (Of n) IO ()+> mapsM (fold' mappend mempty id) :: Stream (Stream (Of Int)) IO () -> Stream (Of Int) IO ()++>>> S.print $ mapsM sum' $ chunksOf 3 $ each [1..10]+6+15+24+10++>>> let three_folds = L.purely S.fold' (liftA3 (,,) L.sum L.product L.list)+>>> S.print $ mapsM three_folds $ chunksOf 3 (each [1..10])+(6,6,[1,2,3])+(15,120,[4,5,6])+(24,504,[7,8,9])+(10,10,[10]) -} {-| Strict fold of a 'Stream' of elements@@ -377,16 +402,44 @@ Step (a :> rest) -> loop rest (step x a) {-# INLINABLE fold #-} -{-| Strict fold of a 'Stream' of elements that preserves the return value+{-| Strict fold of a 'Stream' of elements that preserves the return value. -> Control.Foldl.purely fold' :: Monad m => Fold a b -> Stream (Of a) m r -> m (b, r)+>>> S.sum' $ each [1..10]+55 :> ()++>>> (n :> rest) <- sum' $ S.splitAt 3 (each [1..10])+>>> print n+6+>>> (m :> rest') <- sum' $ S.splitAt 3 rest+>>> print m+15+>>> S.print rest'+7+8+9++ The type provides for interoperation with the foldl library.++> Control.Foldl.purely fold' :: Monad m => Fold a b -> Stream (Of a) m r -> m (Of b r)++ Thus, specializing a bit:++> L.purely fold' L.sum :: Stream (Of Int) Int r -> m (Of Int r)+> maps (L.purely fold' L.sum) :: Stream (Stream (Of Int)) IO r -> Stream (Of Int) IO r+++>>> S.print $ mapsM (L.purely S.fold' (liftA2 (,) L.list L.sum)) $ chunksOf 3 $ each [1..10]+([1,2,3],6)+([4,5,6],15)+([7,8,9],24)+([10],10) -} -fold' :: Monad m => (x -> a -> x) -> x -> (x -> b) -> Stream (Of a) m r -> m (b, r)+fold' :: Monad m => (x -> a -> x) -> x -> (x -> b) -> Stream (Of a) m r -> m (Of b r) fold' step begin done s0 = loop s0 begin where loop stream !x = case stream of - Return r -> return (done x, r)+ Return r -> return (done x :> r) Delay m -> m >>= \s -> loop s x Step (a :> rest) -> loop rest (step x a) {-# INLINABLE fold' #-}@@ -416,13 +469,13 @@ -} foldM' :: Monad m- => (x -> a -> m x) -> m x -> (x -> m b) -> Stream (Of a) m r -> m (b, r)+ => (x -> a -> m x) -> m x -> (x -> m b) -> Stream (Of a) m r -> m (Of b r) foldM' step begin done str = do x0 <- begin loop str x0 where loop stream !x = case stream of - Return r -> done x >>= \b -> return (b, r)+ Return r -> done x >>= \b -> return (b :> r) Delay m -> m >>= \s -> loop s x Step (a :> rest) -> do x' <- step x a@@ -551,24 +604,8 @@ f a loop as {-# INLINEABLE mapM_ #-}-{-| Map free layers of a functor to a corresponding stream of individual elements. This- simplifies the use of folds marked with a \'\'\' in @Streaming.Prelude@ -> maps' sum' :: (Monad m, Num a) => Stream (Stream (Of a) m) m r -> Stream (Of a) m r-> maps' (Pipes.fold' (+) (0::Int) id) :: Monad m => Stream (Producer Int m) m r -> Stream (Of Int) m r --}-maps' :: (Monad m, Functor f) - => (forall x . f x -> m (a, x)) - -> Stream f m r - -> Stream (Of a) m r-maps' phi = loop where- loop stream = case stream of - Return r -> Return r- Delay m -> Delay $ liftM loop m- Step fs -> Delay $ liftM (Step . uncurry (:>)) (phi (fmap loop fs))-{-# INLINABLE maps' #-}- {-| The standard way of inspecting the first item in a stream of elements, if the stream is still \'running\'. The @Right@ case contains a Haskell pair, where the more general @inspect@ would return a left-strict pair. @@ -624,7 +661,7 @@ > maps' product' :: Stream (Stream (Of Int)) m r -> Stream (Of Int) m r -}-product' :: (Monad m, Num a) => Stream (Of a) m r -> m (a,r)+product' :: (Monad m, Num a) => Stream (Of a) m r -> m (Of a r) product' = fold' (*) 1 id {-# INLINAE product' #-} @@ -800,7 +837,7 @@ > maps' sum' :: Stream (Stream (Of Int)) m r -> Stream (Of Int) m r -}-sum' :: (Monad m, Num a) => Stream (Of a) m r -> m (a, r)+sum' :: (Monad m, Num a) => Stream (Of a) m r -> m (Of a r) sum' = fold' (+) 0 id {-# INLINE sum' #-} @@ -859,9 +896,23 @@ -- take -- --------------- --- | End stream after n elements; the original return value is lost.--- 'splitAt' preserves this information. Note the function is functor-general.+{-| End a stream after n elements; the original return value is thus lost.+ 'splitAt' preserves this information. Note that, like @splitAt@, this+ function is functor-general, so that, for example, you can @take@ not+ just a number of items from a stream of elements, but a number + of substreams and the like. +>>> S.print $ mapsM sum' $ S.take 2 $ chunksOf 3 $ each [1..]+6 -- sum of first group of 3+15 -- sum of second group of 3+>>> S.print $ mapsM S.sum' $ S.take 2 $ chunksOf 3 $ S.each [1..4] >> S.readLn+6 -- sum of first group of 3, which is already in [1..4]+100 -- user input+10000 -- user input+10104 -- sum of second group of 3++-}+ take :: (Monad m, Functor f) => Int -> Stream f m r -> Stream f m () take = loop where loop n p = when (n > 0) $@@ -913,7 +964,7 @@ > maps' toListM' :: Stream (Stream (Of a)) m r -> Stream (Of [a]) m -}-toListM' :: Monad m => Stream (Of a) m r -> m ([a], r)+toListM' :: Monad m => Stream (Of a) m r -> m (Of [a] r) toListM' = fold' (\diff a ls -> diff (a: ls)) id (\diff -> diff []) {-# INLINE toListM' #-} @@ -942,12 +993,12 @@ {-| A singleton stream ->>> S.sum $ do {S.yield 1; lift $ putStrLn "hello"; S.yield 2; lift $ putStrLn "goodbye"; S.yield 3}+>>> S.sum $ do {yield 1; lift (putStrLn "hello"); yield 2; lift (putStrLn "goodbye"); S.yield 3} hello goodbye 6 ->>> S.sum $ S.take 3 $ forever $ do {lift $ putStrLn "enter a number" ; n <- lift $ readLn; S.yield n }+>>> S.sum $ S.take 3 $ forever $ do {lift (putStrLn "enter a number") ; n <- lift readLn; S.yield n } enter a number 100 enter a number
streaming.cabal view
@@ -1,32 +1,28 @@ name: streaming-version: 0.1.0.5+version: 0.1.0.6 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- is better able to optimize operations written in- terms of `Stream`.- .- See the examples in @Streaming.Prelude@ for a sense- of how simple the library is to use and think about. +description: `Stream` can be used wherever `FreeT` is used. The compiler's+ standard range of optimizations work better for operations + written in terms of `Stream`. See the examples in @Streaming.Prelude@ + for a sense of how simple the library is to use and think about.+ . @Streaming.Prelude@ closely follows - @Pipes.Prelude@, but cleverly omits the pipes. It is focused + @Pipes.Prelude@, but cleverly /omits the pipes/. It is focused on employment with a base functors which generate- effectful sequences: i.e., things like - .- * @Pipes.Producer@- . - * @Conduit.Source@+ effectful sequences: e.g. .- * @IOStreams.InputStream@+ > 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 .- * @IOStreams.Generator@+ and the like. . Interoperation with <http://hackage.haskell.org/package/pipes pipes>- is accomplished with this isomorphism which- uses @Pipes.Prelude.unfoldr@ from @HEAD@:+ 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 @@ -40,7 +36,11 @@ > Streaming.reread IOStreams.read :: InputStream a -> Stream (Of a) IO () > IOStreams.unfoldM Streaming.uncons :: Stream (Of a) IO () -> IO (InputStream a) .- for example. A simple exit to <http://hackage.haskell.org/package/conduit conduit> would be, e.g.:+ The purposes of the separate @Generator a r@ type can as well be met with + @Stream (Of a) m r@, which admits more complex manipulations and should+ be somewhat friendlier to the compiler. + .+ 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 .