streaming 0.2.2.0 → 0.2.3.0
raw patch · 7 files changed
+486/−499 lines, 7 filesdep +faildep ~basedep ~transformers
Dependencies added: fail
Dependency ranges changed: base, transformers
Files
- README.md +1/−1
- changelog.md +19/−2
- src/Data/Functor/Of.hs +23/−19
- src/Streaming.hs +7/−10
- src/Streaming/Internal.hs +151/−130
- src/Streaming/Prelude.hs +259/−309
- streaming.cabal +26/−28
README.md view
@@ -255,7 +255,7 @@ Rather than wrapping each step in a monadic 'layer', such a layer is put alongside separate 'pure' constructors for a functor 'layer' and a final return value. The maneuver is very friendly to the compiler, but requires a bit of subtlety to protect a sound monad instance. Just such an optimization is adopted internally by the `pipes` library. As in `pipes`, the constructors are here left in an `Internal` module; the main `Streaming` module exporting the type itself and various operations and instances. -I ran a simple [benchmark](https://gist.github.com/michaelt/ee3710c5bab9b7d0892bd552e0eedfd9) (adjusting a [script](https://github.com/jwiegley/streaming-tests) of John Weigly) using a very simple composition of functions:+I ran a simple [benchmark](https://gist.github.com/michaelt/ee3710c5bab9b7d0892bd552e0eedfd9) (adjusting a [script](https://github.com/jwiegley/streaming-tests) of John Wiegley) using a very simple composition of functions: toList . filter (\x -> x `mod` 2 == 0)
changelog.md view
@@ -1,6 +1,23 @@-- ???+- 0.2.3.0+ Add `wrapEffect`. - Added `nubOrd`, `nubInt`, `nubOrdOn`, `nubIntOn`.+ Compatibility with base 4.13.+ + Provide a MonadFail instance for Stream.++ Only depend on `semigroups` on old GHCs.++ Add `untilLeft` (counterpart to `untilRight`)++ Add doctests.++ Enable -Wall in cabal file.++ Build with ghc >= 7.10.3.++- 0.2.2.0++ Add `nubOrd`, `nubInt`, `nubOrdOn`, `nubIntOn`. Fix performance regression in `for`.
src/Data/Functor/Of.hs view
@@ -1,18 +1,19 @@ {-# LANGUAGE CPP, DeriveDataTypeable, DeriveTraversable, DeriveFoldable, DeriveGeneric #-}-module Data.Functor.Of where+module Data.Functor.Of (Of(..)) where import Data.Monoid (Monoid (..)) import Data.Semigroup (Semigroup (..)) import Control.Applicative import Data.Traversable (Traversable) import Data.Foldable (Foldable)-#if MIN_VERSION_base(4,8,0) import Data.Bifunctor-#endif import Data.Data-import Data.Typeable-import GHC.Generics (Generic, Generic1)+#if MIN_VERSION_base(4,9,0) import Data.Functor.Classes+import Data.Foldable (Foldable)+import Data.Traversable (Traversable)+#endif+import GHC.Generics (Generic, Generic1) -- | A left-strict pair; the base functor for streams of individual elements. data Of a b = !a :> b@@ -35,7 +36,7 @@ instance Functor (Of a) where fmap f (a :> x) = a :> f x {-#INLINE fmap #-}- a <$ (b :> x) = b :> a+ a <$ (b :> _) = b :> a {-#INLINE (<$) #-} #if MIN_VERSION_base(4,8,0)@@ -51,24 +52,31 @@ instance Monoid a => Applicative (Of a) where pure x = mempty :> x {-#INLINE pure #-}- m :> f <*> m' :> x = mappend m m' :> f x+ (m :> f) <*> (m' :> x) = mappend m m' :> f x {-#INLINE (<*>) #-}- m :> x *> m' :> y = mappend m m' :> y+ (m :> _) *> (m' :> y) = mappend m m' :> y {-#INLINE (*>) #-}- m :> x <* m' :> y = mappend m m' :> x+ (m :> x) <* (m' :> _) = mappend m m' :> x {-#INLINE (<*) #-} instance Monoid a => Monad (Of a) where- return x = mempty :> x+ return = pure {-#INLINE return #-}- m :> x >> m' :> y = mappend m m' :> y+ (m :> _) >> (m' :> y) = mappend m m' :> y {-#INLINE (>>) #-}- m :> x >>= f = let m' :> y = f x in mappend m m' :> y+ (m :> x) >>= f = let m' :> y = f x in mappend m m' :> y {-#INLINE (>>=) #-} +#if MIN_VERSION_base(4,9,0) instance Show a => Show1 (Of a) where liftShowsPrec = liftShowsPrec2 showsPrec showList +instance Eq a => Eq1 (Of a) where+ liftEq = liftEq2 (==)++instance Ord a => Ord1 (Of a) where+ liftCompare = liftCompare2 compare+ instance Show2 Of where liftShowsPrec2 spa _sla spb _slb p (a :> b) = showParen (p > 5) $@@ -76,15 +84,11 @@ showString " :> " . spb 6 b -instance Eq a => Eq1 (Of a) where- liftEq = liftEq2 (==)--instance Ord a => Ord1 (Of a) where- liftCompare = liftCompare2 compare- instance Eq2 Of where- liftEq2 eq1 eq2 (x :> y) (z :> w) = eq1 x z && eq2 y w+ liftEq2 f g (x :> y) (z :> w) = f x z && g y w instance Ord2 Of where liftCompare2 comp1 comp2 (x :> y) (z :> w) = comp1 x z `mappend` comp2 y w+#endif+
src/Streaming.hs view
@@ -1,6 +1,5 @@ {-# LANGUAGE RankNTypes #-} -{-# OPTIONS_GHC -Wall #-} module Streaming ( -- * An iterable streaming monad transformer@@ -115,10 +114,10 @@ Some of these are quite abstract and pervade any use of the library, e.g. -> maps :: (forall x . f x -> g x) -> Stream f m r -> Stream g m r-> mapped :: (forall x . f x -> m (g x)) -> Stream f m r -> Stream g m r-> hoist :: (forall x . m x -> n x) -> Stream f m r -> Stream f n r -- from the MFunctor instance-> concats :: Stream (Stream f m) m r -> Stream f m r +> maps :: (forall x . f x -> g x) -> Stream f m r -> Stream g m r+> mapped :: (forall x . f x -> m (g x)) -> Stream f m r -> Stream g m r+> hoist :: (forall x . m x -> n x) -> Stream f m r -> Stream f n r -- from the MFunctor instance+> concats :: Stream (Stream f m) m r -> Stream f m r (assuming here and thoughout that @m@ or @n@ satisfies a @Monad@ constraint, and @f@ or @g@ a @Functor@ constraint.)@@ -128,12 +127,12 @@ > chunksOf :: Int -> Stream f m r -> Stream (Stream f m) m r > splitsAt :: Int -> Stream f m r -> Stream f m (Stream f m r) > zipsWith :: (forall x y. f x -> g y -> h (x, y))- -> Stream f m r -> Stream g m r -> Stream h m r+> -> Stream f m r -> Stream g m r -> Stream h m r > zipsWith' :: (forall x y p. (x -> y -> p) -> f x -> g y -> h p)- -> Stream f m r -> Stream g m r -> Stream h m r+> -> Stream f m r -> Stream g m r -> Stream h m r > intercalates :: Stream f m () -> Stream (Stream f m) m r -> Stream f m r > unzips :: Stream (Compose f g) m r -> Stream f (Stream g m) r-> separate :: Stream (Sum f g) m r -> Stream f (Stream g) m r -- cp. partitionEithers+> separate :: Stream (Sum f g) m r -> Stream f (Stream g m) r -- cp. partitionEithers > unseparate :: Stream f (Stream g) m r -> Stream (Sum f g) m r > groups :: Stream (Sum f g) m r -> Stream (Sum (Stream f m) (Stream g m)) m r @@ -168,5 +167,3 @@ > concats :: (Monad m, MonadTrans t, Monad (t m)) => Stream (t m) m a -> t m a > concats stream = destroy stream join (join . lift) return -}--
src/Streaming/Internal.hs view
@@ -1,20 +1,17 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE GADTs #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-} {-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE StandaloneDeriving #-}-{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE UndecidableInstances #-} -{-# OPTIONS_GHC -Wall #-} module Streaming.Internal ( -- * The free monad transformer -- $stream Stream (..)- + -- * Introducing a stream , unfold , replicates@@ -28,7 +25,7 @@ , delays , never , untilJust- + -- * Eliminating a stream , intercalates , concats@@ -36,10 +33,10 @@ , iterTM , destroy , streamFold- + -- * Inspecting a stream wrap by wrap , inspect- + -- * Transforming streams , maps , mapsM@@ -52,7 +49,7 @@ , distribute , groups -- , groupInL- + -- * Splitting streams , chunksOf , splitsAt@@ -60,7 +57,7 @@ , cutoff -- , period -- , periods- + -- * Zipping and unzipping streams , zipsWith , zipsWith'@@ -72,10 +69,10 @@ , expand , expandPost - + -- * Assorted Data.Functor.x help , switch- + -- * For use in implementation , unexposed , hoistExposed@@ -83,25 +80,29 @@ , mapsExposed , mapsMExposed , destroyExposed- + ) where +import Control.Applicative+import Control.Concurrent (threadDelay) import Control.Monad-import Control.Monad.Trans-import Control.Monad.Reader.Class-import Control.Monad.State.Class import Control.Monad.Error.Class-import Control.Applicative-import Data.Function ( on )+import Control.Monad.Fail as Fail import Control.Monad.Morph-import Data.Monoid (Monoid (..))-import Data.Semigroup (Semigroup (..))+import Control.Monad.Reader.Class+import Control.Monad.State.Class+import Control.Monad.Trans import Data.Data (Typeable)-import Prelude hiding (splitAt)+import Data.Function ( on )+import Data.Functor.Classes import Data.Functor.Compose import Data.Functor.Sum-import Data.Functor.Classes-import Control.Concurrent (threadDelay)+import Data.Monoid (Monoid (..))+import Data.Semigroup (Semigroup (..))++-- $setup+-- >>> import Streaming.Prelude as S+ {- $stream The 'Stream' data type is equivalent to @FreeT@ and can represent any effectful@@ -157,6 +158,8 @@ (<=) = (<=) `on` inspect (>=) = (>=) `on` inspect +#if MIN_VERSION_base(4,9,0)+ -- We could avoid a Show1 constraint for our Show1 instance by sneakily -- mapping everything to a single known type, but there's really no way -- to do that for Eq1 or Ord1.@@ -165,7 +168,7 @@ where liftEqExposed (Return x) (Return y) = eq x y liftEqExposed (Effect m) (Effect n) = liftEq liftEqExposed m n- liftEqExposed (Step f) (Step g) = liftEq liftEqExposed f g+ liftEqExposed (Step f) (Step g) = liftEq liftEqExposed f g liftEqExposed _ _ = False instance (Monad m, Functor f, Ord1 m, Ord1 f) => Ord1 (Stream f m) where@@ -173,11 +176,13 @@ where liftCmpExposed (Return x) (Return y) = cmp x y liftCmpExposed (Effect m) (Effect n) = liftCompare liftCmpExposed m n- liftCmpExposed (Step f) (Step g) = liftCompare liftCmpExposed f g+ liftCmpExposed (Step f) (Step g) = liftCompare liftCmpExposed f g liftCmpExposed (Return _) _ = LT liftCmpExposed _ (Return _) = GT liftCmpExposed _ _ = error "liftCmpExposed: stream was exposed!" +#endif+ -- We could get a much less scary implementation using Show1, but -- Show1 instances aren't nearly as common as Show instances. --@@ -196,9 +201,11 @@ flip fmap (inspect xs) $ \front -> SS $ \d -> showParen (d > 10) $ case front of- Left r -> showString "Return " . showsPrec 11 r+ Left r -> showString "Return " . showsPrec 11 r Right f -> showString "Step " . showsPrec 11 f) +#if MIN_VERSION_base(4,9,0)+ instance (Monad m, Functor f, Show (m ShowSWrapper), Show (f ShowSWrapper)) => Show1 (Stream f m) where liftShowsPrec sp sl p xs = showParen (p > 10) $@@ -206,47 +213,62 @@ flip fmap (inspect xs) $ \front -> SS $ \d -> showParen (d > 10) $ case front of- Left r -> showString "Return " . sp 11 r+ Left r -> showString "Return " . sp 11 r Right f -> showString "Step " . showsPrec 11 (fmap (SS . (\str i -> liftShowsPrec sp sl i str)) f)) +#endif+ newtype ShowSWrapper = SS (Int -> ShowS) instance Show ShowSWrapper where showsPrec p (SS s) = s p +-- | Operates covariantly on the stream result, not on its elements:+--+-- @+-- Stream (Of a) m r+-- ^ ^+-- | `--- This is what `Functor` and `Applicative` use+-- `--- This is what functions like S.map/S.zipWith use+-- @ instance (Functor f, Monad m) => Functor (Stream f m) where fmap f = loop where loop stream = case stream of Return r -> Return (f r)- Effect m -> Effect (do {stream' <- m; return (loop stream')})- Step g -> Step (fmap loop g)+ Effect m -> Effect (do {stream' <- m; return (loop stream')})+ Step g -> Step (fmap loop g) {-# INLINABLE fmap #-} a <$ stream0 = loop stream0 where loop stream = case stream of Return _ -> Return a Effect m -> Effect (do {stream' <- m; return (loop stream')})- Step f -> Step (fmap loop f)- {-# INLINABLE (<$) #-} + Step f -> Step (fmap loop f)+ {-# INLINABLE (<$) #-} instance (Functor f, Monad m) => Monad (Stream f m) where- return = Return+ return = pure {-# INLINE return #-} (>>) = (*>) {-# INLINE (>>) #-} -- (>>=) = _bind- -- {-#INLINE (>>=) #-}+ -- {-# INLINE (>>=) #-} -- stream >>= f = loop stream where loop stream0 = case stream0 of Step fstr -> Step (fmap loop fstr)- Effect m -> Effect (fmap loop m)+ Effect m -> Effect (fmap loop m) Return r -> f r- {-# INLINABLE (>>=) #-} + {-# INLINABLE (>>=) #-} - fail = lift . fail- {-#INLINE fail #-}+#if !(MIN_VERSION_base(4,13,0))+ fail = lift . Prelude.fail+ {-# INLINE fail #-}+#endif +instance (Functor f, MonadFail m) => MonadFail (Stream f m) where+ fail = lift . Fail.fail+ {-# INLINE fail #-} -- _bind -- :: (Functor f, Monad m)@@ -258,7 +280,7 @@ -- Step fstr -> Step (fmap go fstr) -- Effect m -> Effect (m >>= \s -> return (go s)) -- Return r -> f r--- {-#INLINABLE _bind #-}+-- {-# INLINABLE _bind #-} -- -- see https://github.com/Gabriel439/Haskell-Pipes-Library/pull/163 -- for a plan to delay inlining and manage interaction with other operations.@@ -275,12 +297,12 @@ instance (Functor f, Monad m) => Applicative (Stream f m) where pure = Return {-# INLINE pure #-}- streamf <*> streamx = do {f <- streamf; x <- streamx; return (f x)} - {-# INLINE (<*>) #-} + streamf <*> streamx = do {f <- streamf; x <- streamx; return (f x)}+ {-# INLINE (<*>) #-} stream1 *> stream2 = loop stream1 where loop stream = case stream of Return _ -> stream2- Effect m -> Effect (fmap loop m)+ Effect m -> Effect (fmap loop m) Step f -> Step (fmap loop f) {-# INLINABLE (*>) #-} @@ -294,21 +316,21 @@ -} instance (Applicative f, Monad m) => Alternative (Stream f m) where empty = never- {-#INLINE empty #-}+ {-# INLINE empty #-} str <|> str' = zipsWith' liftA2 str str'- {-#INLINE (<|>) #-}+ {-# INLINE (<|>) #-} instance (Functor f, Monad m, Semigroup w) => Semigroup (Stream f m w) where a <> b = a >>= \w -> fmap (w <>) b- {-#INLINE (<>) #-}+ {-# INLINE (<>) #-} instance (Functor f, Monad m, Monoid w) => Monoid (Stream f m w) where mempty = return mempty- {-#INLINE mempty #-}+ {-# INLINE mempty #-} #if !(MIN_VERSION_base(4,11,0)) mappend a b = a >>= \w -> fmap (w `mappend`) b- {-#INLINE mappend #-}+ {-# INLINE mappend #-} #endif instance (Applicative f, Monad m) => MonadPlus (Stream f m) where@@ -322,17 +344,17 @@ instance Functor f => MFunctor (Stream f) where hoist trans = loop where loop stream = case stream of- Return r -> Return r- Effect m -> Effect (trans (fmap loop m))- Step f -> Step (fmap loop f)- {-# INLINABLE hoist #-} + Return r -> Return r+ Effect m -> Effect (trans (fmap loop m))+ Step f -> Step (fmap loop f)+ {-# INLINABLE hoist #-} instance Functor f => MMonad (Stream f) where embed phi = loop where loop stream = case stream of Return r -> Return r- Effect m -> phi m >>= loop+ Effect m -> phi m >>= loop Step f -> Step (fmap loop f) {-# INLINABLE embed #-} @@ -345,7 +367,7 @@ {-# INLINE ask #-} local f = hoist (local f) {-# INLINE local #-}- + instance (Functor f, MonadState s m) => MonadState s (Stream f m) where get = lift get {-# INLINE get #-}@@ -363,7 +385,7 @@ loop x = case x of Return r -> Return r Effect m -> Effect $ fmap loop m `catchError` (return . f)- Step g -> Step (fmap loop g)+ Step g -> Step (fmap loop g) {-# INLINABLE catchError #-} {-| Map a stream to its church encoding; compare @Data.List.foldr@.@@ -382,7 +404,7 @@ loop stream = case stream of Return r -> return (done r) Effect m -> m >>= loop- Step fs -> return (construct (fmap (theEffect . loop) fs))+ Step fs -> return (construct (fmap (theEffect . loop) fs)) {-# INLINABLE destroy #-} @@ -421,11 +443,11 @@ :: (Functor f, Monad m) => (r -> b) -> (m b -> b) -> (f b -> b) -> Stream f m r -> b streamFold done theEffect construct stream = destroy stream construct theEffect done-{-#INLINE streamFold #-}+{-# INLINE streamFold #-} {- | Reflect a church-encoded stream; cp. @GHC.Exts.build@ -> streamFold return_ effect_ step_ (streamBuild psi) = psi return_ effect_ step_+> streamFold return_ effect_ step_ (streamBuild psi) = psi return_ effect_ step_ -} streamBuild :: (forall b . (r -> b) -> (m b -> b) -> (f b -> b) -> b) -> Stream f m r@@ -445,10 +467,10 @@ inspect = loop where loop stream = case stream of Return r -> return (Left r)- Effect m -> m >>= loop+ Effect m -> m >>= loop Step fs -> return (Right fs) {-# INLINABLE inspect #-}- + {-| Build a @Stream@ by unfolding steps starting from a seed. See also the specialized 'Streaming.Prelude.unfoldr' in the prelude. @@ -463,9 +485,9 @@ unfold step = loop where loop s0 = Effect $ do e <- step s0- case e of- Left r -> return (Return r)- Right fs -> return (Step (fmap loop fs))+ return $ case e of+ Left r -> Return r+ Right fs -> Step (fmap loop fs) {-# INLINABLE unfold #-} @@ -480,9 +502,9 @@ => (forall x . f x -> g x) -> Stream f m r -> Stream g m r maps phi = loop where loop stream = case stream of- Return r -> Return r- Effect m -> Effect (fmap loop m)- Step f -> Step (phi (fmap loop f))+ Return r -> Return r+ Effect m -> Effect (fmap loop m)+ Step f -> Step (phi (fmap loop f)) {-# INLINABLE maps #-} @@ -499,9 +521,9 @@ 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- Return r -> Return r- Effect m -> Effect (fmap loop m)- Step f -> Effect (fmap Step (phi (fmap loop f)))+ Return r -> Return r+ Effect m -> Effect (fmap loop m)+ Step f -> Effect (fmap Step (phi (fmap loop f))) {-# INLINABLE mapsM #-} {- | Map layers of one functor to another with a transformation. Compare@@ -509,8 +531,7 @@ > mapsPost id = id > mapsPost f . mapsPost g = mapsPost (f . g)-> mapsPost f = mapsPost f-+> mapsPost f = maps f @mapsPost@ is essentially the same as 'maps', but it imposes a 'Functor' constraint on its target functor rather than its source functor. It should be preferred if 'fmap'@@ -524,7 +545,7 @@ loop stream = case stream of Return r -> Return r Effect m -> Effect (fmap loop m)- Step f -> Step $ fmap loop $ phi f+ Step f -> Step $ fmap loop $ phi f {-# INLINABLE mapsPost #-} {- | Map layers of one functor to another with a transformation involving the base monad.@@ -549,7 +570,7 @@ loop stream = case stream of Return r -> Return r Effect m -> Effect (fmap loop m)- Step f -> Effect $ fmap (Step . fmap loop) (phi f)+ Step f -> Effect $ fmap (Step . fmap loop) (phi f) {-# INLINABLE mapsMPost #-} {-| Rearrange a succession of layers of the form @Compose m (f x)@.@@ -573,7 +594,7 @@ decompose = loop where loop stream = case stream of Return r -> Return r- Effect m -> Effect (fmap loop m)+ Effect m -> Effect (fmap loop m) Step (Compose mstr) -> Effect $ do str <- mstr return (Step (fmap loop str))@@ -584,8 +605,8 @@ run :: Monad m => Stream m m r -> m r run = loop where loop stream = case stream of- Return r -> return r- Effect m -> m >>= loop+ Return r -> return r+ Effect m -> m >>= loop Step mrest -> mrest >>= loop {-# INLINABLE run #-} @@ -606,16 +627,16 @@ intercalates sep = go0 where go0 f = case f of- Return r -> return r- Effect m -> lift m >>= go0+ Return r -> return r+ Effect m -> lift m >>= go0 Step fstr -> do f' <- fstr go1 f' go1 f = case f of- Return r -> return r- Effect m -> lift m >>= go1+ Return r -> return r+ Effect m -> lift m >>= go1 Step fstr -> do- _ <- sep+ _ <- sep f' <- fstr go1 f' {-# INLINABLE intercalates #-}@@ -649,7 +670,7 @@ concats = loop where loop stream = case stream of Return r -> return r- Effect m -> lift m >>= loop+ Effect m -> lift m >>= loop Step fs -> fs >>= loop {-# INLINE concats #-} @@ -679,11 +700,11 @@ splitsAt :: (Monad m, Functor f) => Int -> Stream f m r -> Stream f m (Stream f m r) splitsAt = loop where loop !n stream- | n <= 0 = Return stream+ | n <= 0 = Return stream | otherwise = case stream of- Return r -> Return (Return r)- Effect m -> Effect (fmap (loop n) m)- Step fs -> case n of+ Return r -> Return (Return r)+ Effect m -> Effect (fmap (loop n) m)+ Step fs -> case n of 0 -> Return (Step fs) _ -> Step (fmap (loop (n-1)) fs) {-# INLINABLE splitsAt #-}@@ -716,7 +737,7 @@ -} takes :: (Monad m, Functor f) => Int -> Stream f m r -> Stream f m () takes n = void . splitsAt n-{-# INLINE takes #-} +{-# INLINE takes #-} {-| Break a stream into substreams each with n functorial layers. @@ -731,7 +752,7 @@ Return r -> Return r Effect m -> Effect (fmap loop m) Step fs -> Step (Step (fmap (fmap loop . splitsAt (n0-1)) fs))-{-# INLINABLE chunksOf #-} +{-# INLINABLE chunksOf #-} {- | Make it possible to \'run\' the underlying transformed monad. -}@@ -742,19 +763,19 @@ Return r -> lift (Return r) Effect tmstr -> hoist lift tmstr >>= loop Step fstr -> join (lift (Step (fmap (Return . loop) fstr)))-{-#INLINABLE distribute #-}- +{-# INLINABLE distribute #-}+ -- | Repeat a functorial layer (a \"command\" or \"instruction\") forever. repeats :: (Monad m, Functor f) => f () -> Stream f m r repeats f = loop where- loop = Effect (return (Step (fmap (\_ -> loop) f)))+ loop = Effect (return (Step (loop <$ f))) -- | Repeat an effect containing a functorial layer, command or instruction forever. repeatsM :: (Monad m, Functor f) => m (f ()) -> Stream f m r repeatsM mf = loop where loop = Effect $ do f <- mf- return $ Step $ fmap (\_ -> loop) f+ return $ Step $ loop <$ f {- | Repeat a functorial layer, command or instruction a fixed number of times. @@ -788,7 +809,7 @@ inspectC :: Monad m => (r -> m a) -> (f (Stream f m r) -> m a) -> Stream f m r -> m a inspectC f g = loop where loop (Return r) = f r- loop (Step x) = g x+ loop (Step x) = g x loop (Effect m) = m >>= loop {-# INLINE inspectC #-} @@ -798,9 +819,9 @@ hoistExposed :: (Functor m, Functor f) => (forall b. m b -> n b) -> Stream f m a -> Stream f n a hoistExposed trans = loop where loop stream = case stream of- Return r -> Return r- Effect m -> Effect (trans (fmap loop m))- Step f -> Step (fmap loop f)+ Return r -> Return r+ Effect m -> Effect (trans (fmap loop m))+ Step f -> Step (fmap loop f) {-# INLINABLE hoistExposed #-} -- | The same as 'hoistExposed', but with a 'Functor' constraint on@@ -811,7 +832,7 @@ loop stream = case stream of Return r -> Return r Effect m -> Effect (fmap loop (trans m))- Step f -> Step (fmap loop f)+ Step f -> Step (fmap loop f) {-# INLINABLE hoistExposedPost #-} {-# DEPRECATED mapsExposed "Use maps instead." #-}@@ -844,7 +865,7 @@ destroyExposed stream0 construct theEffect done = loop stream0 where loop stream = case stream of Return r -> done r- Effect m -> theEffect (fmap loop m)+ Effect m -> theEffect (fmap loop m) Step fs -> construct (fmap loop fs) {-# INLINABLE destroyExposed #-} @@ -858,9 +879,9 @@ unexposed = Effect . loop where loop stream = case stream of Return r -> return (Return r)- Effect m -> m >>= loop+ Effect m -> m >>= loop Step f -> return (Step (fmap (Effect . loop) f))-{-# INLINABLE unexposed #-} +{-# INLINABLE unexposed #-} {-| Wrap a new layer of a stream. So, e.g.@@ -889,7 +910,7 @@ -} wrap :: (Monad m, Functor f ) => f (Stream f m r) -> Stream f m r wrap = Step-{-#INLINE wrap #-}+{-# INLINE wrap #-} {- | Wrap an effect that returns a stream@@ -899,7 +920,7 @@ -} effect :: (Monad m, Functor f ) => m (Stream f m r) -> Stream f m r effect = Effect-{-#INLINE effect #-}+{-# INLINE effect #-} {-| @yields@ is like @lift@ for items in the streamed functor.@@ -916,7 +937,7 @@ yields :: (Monad m, Functor f) => f r -> Stream f m r yields fr = Step (fmap Return fr)-{-#INLINE yields #-}+{-# INLINE yields #-} {- Note that if the first stream produces Return, we don't inspect@@ -966,9 +987,9 @@ loop :: Stream f m r -> Stream g m r -> Stream h m r loop s t = case s of Return r -> Return r- Step fs -> case t of+ Step fs -> case t of Return r -> Return r- Step gs -> Step $ phi loop fs gs+ Step gs -> Step $ phi loop fs gs Effect n -> Effect $ fmap (loop s) n Effect m -> Effect $ fmap (flip loop t) m {-# INLINABLE zipsWith' #-}@@ -977,7 +998,7 @@ => Stream f m r -> Stream g m r -> Stream (Compose f g) m r zips = zipsWith' go where go p fx gy = Compose (fmap (\x -> fmap (\y -> p x y) gy) fx)-{-# INLINE zips #-} +{-# INLINE zips #-} @@ -998,7 +1019,7 @@ :: (Monad m, Applicative h) => Stream h m r -> Stream h m r -> Stream h m r interleaves = zipsWith' liftA2-{-# INLINE interleaves #-} +{-# INLINE interleaves #-} {-| Swap the order of functors in a sum of functors.@@ -1016,7 +1037,7 @@ -} switch :: Sum f g r -> Sum g f r switch s = case s of InL a -> InR a; InR a -> InL a-{-#INLINE switch #-}+{-# INLINE switch #-} @@ -1033,13 +1054,13 @@ Now, for example, it is convenient to fold on the left and right values separately: ->>> S.toList $ S.toList $ separate odd_even+>>> S.toList $ S.toList $ separate odd_even [2,4,6,8,10] :> ([1,3,5,7,9] :> ()) Or we can write them to separate files or whatever: ->>> runResourceT $ S.writeFile "even.txt" . S.show $ S.writeFile "odd.txt" . S.show $ S.separate odd_even+>>> S.writeFile "even.txt" . S.show $ S.writeFile "odd.txt" . S.show $ S.separate odd_even >>> :! cat even.txt 2 4@@ -1070,7 +1091,7 @@ (\x -> case x of InL fss -> wrap fss; InR gss -> effect (yields gss)) (effect . lift) return-{-#INLINABLE separate #-}+{-# INLINABLE separate #-} @@ -1080,7 +1101,7 @@ (wrap . InL) (join . maps InR) return-{-#INLINABLE unseparate #-}+{-# INLINABLE unseparate #-} -- | If 'Of' had a @Comonad@ instance, then we'd have --@@ -1093,7 +1114,7 @@ -> Stream f m r -> Stream g (Stream h m) r expand ext = loop where loop (Return r) = Return r- loop (Step f) = Effect $ Step $ ext (Return . Step) (fmap loop f)+ loop (Step f) = Effect $ Step $ ext (Return . Step) (fmap loop f) loop (Effect m) = Effect $ Effect $ fmap (Return . loop) m {-# INLINABLE expand #-} @@ -1108,7 +1129,7 @@ -> Stream f m r -> Stream g (Stream h m) r expandPost ext = loop where loop (Return r) = Return r- loop (Step f) = Effect $ Step $ ext (Return . Step . fmap loop) f+ loop (Step f) = Effect $ Step $ ext (Return . Step . fmap loop) f loop (Effect m) = Effect $ Effect $ fmap (Return . loop) m {-# INLINABLE expandPost #-} @@ -1119,7 +1140,7 @@ (\(Compose fgstr) -> Step (fmap (Effect . yields) fgstr)) (Effect . lift) return-{-#INLINABLE unzips #-}+{-# INLINABLE unzips #-} {-| Group layers in an alternating stream into adjoining sub-streams of one type or another.@@ -1156,8 +1177,8 @@ Left r -> return (return r) Right (InL fstr) -> return (wrap (InL fstr)) Right (InR gstr) -> wrap (fmap go gstr)-{-#INLINABLE groups #-}- +{-# INLINABLE groups #-}+ -- groupInL :: (Monad m, Functor f, Functor g) -- => Stream (Sum f g) m r -- -> Stream (Sum (Stream f m) g) m r@@ -1249,14 +1270,14 @@ -- The Monad m constraint should really be an Applicative one, -- but we still support old versions of base. never = let loop = Step $ pure (Effect (return loop)) in loop-{-#INLINABLE never #-}+{-# INLINABLE never #-} delays :: (MonadIO m, Applicative f) => Double -> Stream f m r delays seconds = loop where loop = Effect $ liftIO (threadDelay delay) >> return (Step (pure loop)) delay = fromInteger (truncate (1000000 * seconds))-{-#INLINABLE delays #-}+{-# INLINABLE delays #-} -- {-| Permit streamed actions to proceed unless the clock has run out. --@@ -1275,7 +1296,7 @@ -- loop str -- where -- cutoff = fromInteger (truncate (1000000000 * seconds))--- {-#INLINABLE period #-}+-- {-# INLINABLE period #-} -- -- -- {-| Divide a succession of phases according to a specified time interval. If time runs out@@ -1339,11 +1360,11 @@ untilJust act = loop where loop = Effect $ do m <- act- case m of- Nothing -> return $ Step $ pure loop- Just a -> return $ Return a- - + return $ case m of+ Nothing -> Step $ pure loop+ Just a -> Return a++ cutoff :: (Monad m, Functor f) => Int -> Stream f m r -> Stream f m (Maybe r) cutoff = loop where loop 0 _ = return Nothing@@ -1351,4 +1372,4 @@ e <- lift $ inspect str case e of Left r -> return (Just r)- Right (frest) -> Step $ fmap (loop (n-1)) frest+ Right frest -> Step $ fmap (loop (n-1)) frest
src/Streaming/Prelude.hs view
@@ -1,4 +1,4 @@-{-| This names exported by this module are closely modeled on those in @Prelude@ and @Data.List@,+{-| The names exported by this module are closely modeled on those in @Prelude@ and @Data.List@, but also on <http://hackage.haskell.org/package/pipes-4.1.9/docs/Pipes-Prelude.html Pipes.Prelude>, <http://hackage.haskell.org/package/pipes-group-1.0.3/docs/Pipes-Group.html Pipes.Group>@@ -8,7 +8,7 @@ articulated in the latter two modules. Because we dispense with piping and conduiting, the distinction between all of these modules collapses. Some things are lost but much is gained: on the one hand, everything comes much closer to ordinary- beginning Haskell programming and, on the other, acquires the plasticity of programming + beginning Haskell programming and, on the other, acquires the plasticity of programming directly with a general free monad type. The leading type, @Stream (Of a) m r@ is chosen to permit an api that is as close as possible to that of @Data.List@ and the @Prelude@. @@ -47,17 +47,11 @@ > -------------------------------------------------------------------------------------------------------------------- > -}-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE DeriveFoldable #-}-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE DeriveTraversable #-}-{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeFamilies #-}--{-# OPTIONS_GHC -Wall #-}+{-# LANGUAGE TypeFamilies #-} module Streaming.Prelude ( -- * Types@@ -70,21 +64,22 @@ , stdinLn , readLn , fromHandle- , readFile + , readFile , iterate , iterateM , repeat , repeatM , replicate+ , untilLeft , untilRight , cycle , replicateM , enumFrom , enumFromThen , unfoldr- + -- * Consuming streams of elements -- $consumers , stdoutLn@@ -92,7 +87,7 @@ , mapM_ , print , toHandle- , writeFile + , writeFile , effects , erase , drained@@ -138,8 +133,8 @@ , read , show , cons- , slidingWindow -+ , slidingWindow+ , wrapEffect -- * Splitting and inspecting streams of elements , next@@ -235,7 +230,7 @@ , merge , mergeOn , mergeBy- + -- * Maybes -- $maybes , catMaybes@@ -256,19 +251,31 @@ -- * Basic Type , Stream ) where+ import Streaming.Internal +import Control.Applicative (Applicative (..))+import Control.Concurrent (threadDelay)+import Control.Exception (throwIO, try) import Control.Monad hiding (filterM, mapM, mapM_, foldM, foldM_, replicateM, sequence)-import Data.Functor.Identity-import Data.Functor.Sum import Control.Monad.Trans-import Control.Applicative (Applicative (..)) import Data.Functor (Functor (..), (<$))--import qualified Prelude as Prelude+import Data.Functor.Compose+import Data.Functor.Identity+import Data.Functor.Of+import Data.Functor.Sum+import Data.Monoid (Monoid (mappend, mempty))+import Data.Ord (Ordering (..), comparing)+import Foreign.C.Error (Errno(Errno), ePIPE)+import Text.Read (readMaybe) import qualified Data.Foldable as Foldable+import qualified Data.IntSet as IntSet import qualified Data.Sequence as Seq-import Text.Read (readMaybe)+import qualified Data.Set as Set+import qualified GHC.IO.Exception as G+import qualified Prelude+import qualified System.IO as IO+ import Prelude hiding (map, mapM, mapM_, filter, drop, dropWhile, take, mconcat , sum, product, iterate, repeat, cycle, replicate, splitAt , takeWhile, enumFrom, enumFromTo, enumFromThen, length@@ -277,24 +284,26 @@ , minimum, maximum, elem, notElem, all, any, head , last, foldMap) -import qualified GHC.IO.Exception as G-import qualified System.IO as IO-import Foreign.C.Error (Errno(Errno), ePIPE)-import Control.Exception (throwIO, try)-import Data.Monoid (Monoid (mappend, mempty))-import Control.Concurrent (threadDelay)-import Data.Functor.Compose-import Data.Functor.Of-import qualified Data.Set as Set-import qualified Data.IntSet as IntSet-import Data.Ord (Ordering (..), comparing) ++-- $setup+-- >>> import Control.Applicative+-- >>> import qualified Control.Foldl as L+-- >>> import Data.Bifunctor (first)+-- >>> import Data.Function ((&))+-- >>> import Data.IORef+-- >>> import Data.Vector (Vector)+-- >>> import qualified Streaming.Prelude as S+-- >>> import qualified System.IO+-- >>> import Text.Read (readEither)++ -- instance (Eq a) => Eq1 (Of a) where eq1 = (==) -- instance (Ord a) => Ord1 (Of a) where compare1 = compare -- instance (Read a) => Read1 (Of a) where readsPrec1 = readsPrec -- instance (Show a) => Show1 (Of a) where showsPrec1 = showsPrec -{-| Note that 'lazily', 'strictly', 'fst'', and 'mapOf' are all so-called /natural transformations/ on the primitive @Of a@ functor+{-| Note that 'lazily', 'strictly', 'fst'', and 'mapOf' are all so-called /natural transformations/ on the primitive @Of a@ functor. If we write > type f ~~> g = forall x . f x -> g x@@ -319,7 +328,7 @@ This rests on recognizing that @mapOf@ is a natural transformation; note though that it results in such a transformation as well: -> S.map :: (a -> b) -> Stream (Of a) m ~> Stream (Of b) m+> S.map :: (a -> b) -> Stream (Of a) m ~~> Stream (Of b) m Thus we can @maps@ it in turn. @@ -355,10 +364,10 @@ fst' :: Of a b -> a fst' (a :> _) = a-{-#INLINE fst' #-}+{-# INLINE fst' #-} snd' :: Of a b -> b snd' (_ :> b) = b-{-#INLINE snd' #-}+{-# INLINE snd' #-} {-| Map a function over the first element of an @Of@ pair @@ -379,18 +388,18 @@ -} mapOf :: (a -> b) -> Of a r -> Of b r-mapOf f (a:> b) = (f a :> b)-{-#INLINE mapOf #-}+mapOf f (a :> b) = f a :> b+{-# INLINE mapOf #-} {-| A lens into the first element of a left-strict pair -} _first :: Functor f => (a -> f a') -> Of a b -> f (Of a' b)-_first afb (a:>b) = fmap (\c -> (c:>b)) (afb a)+_first afb (a :> b) = fmap (\c -> c :> b) (afb a) {-# INLINE _first #-} {-| A lens into the second element of a left-strict pair -} _second :: Functor f => (b -> f b') -> Of a b -> f (Of a b')-_second afb (a:>b) = fmap (\c -> (a:>c)) (afb b)-{-#INLINABLE _second #-}+_second afb (a :> b) = fmap (\c -> a :> c) (afb b)+{-# INLINABLE _second #-} all :: Monad m => (a -> Bool) -> Stream (Of a) m r -> m (Of Bool r) all thus = loop True where@@ -402,7 +411,7 @@ else do r <- effects rest return (False :> r)-{-#INLINABLE all #-}+{-# INLINABLE all #-} all_ :: Monad m => (a -> Bool) -> Stream (Of a) m r -> m Bool all_ thus = loop True where@@ -412,7 +421,7 @@ Step (a :> rest) -> if thus a then loop True rest else return False-{-#INLINABLE all_ #-}+{-# INLINABLE all_ #-} any :: Monad m => (a -> Bool) -> Stream (Of a) m r -> m (Of Bool r)@@ -425,7 +434,7 @@ r <- effects rest return (True :> r) else loop False rest-{-#INLINABLE any #-}+{-# INLINABLE any #-} any_ :: Monad m => (a -> Bool) -> Stream (Of a) m r -> m Bool any_ thus = loop False where@@ -435,7 +444,7 @@ Step (a :> rest) -> if thus a then return True else loop False rest-{-#INLINABLE any_ #-}+{-# INLINABLE any_ #-} {-| Break a sequence upon meeting element falls under a predicate, keeping it and the rest of the stream as the return value.@@ -454,8 +463,8 @@ break thePred = loop where loop str = case str of Return r -> Return (Return r)- Effect m -> Effect $ fmap loop m- Step (a :> rest) -> if (thePred a)+ Effect m -> Effect $ fmap loop m+ Step (a :> rest) -> if thePred a then Return (Step (a :> rest)) else Step (a :> loop rest) {-# INLINABLE break #-}@@ -465,7 +474,7 @@ and the element that breaks it will be put after the break. This function is easiest to use with 'Control.Foldl.purely' ->>> rest <- each [1..10] & L.purely S.breakWhen L.sum (>10) & S.print+>>> rest <- each [1..10] & L.purely S.breakWhen L.sum (>10) & S.print 1 2 3@@ -486,7 +495,7 @@ Return r -> return (return r) Effect mn -> Effect $ fmap (loop0 x) mn Step (a :> rest) -> loop a (step x a) rest- loop a !x stream = do+ loop a !x stream = if thePred (done x) then return (yield a >> stream) else case stream of@@ -497,17 +506,17 @@ loop a' (step x a') rest {-# INLINABLE breakWhen #-} --- -- Break during periods where the predicate is not satisfied, grouping the periods when it is.------ >>> S.print $ mapped S.toList $ S.breaks not $ S.each [False,True,True,False,True,True,False]--- [True,True]--- [True,True]--- >>> S.print $ mapped S.toList $ S.breaks id $ S.each [False,True,True,False,True,True,False]--- [False]--- [False]--- [False]------ -}+{-| Break during periods where the predicate is not satisfied, grouping the periods when it is.++>>> S.print $ mapped S.toList $ S.breaks not $ S.each [False,True,True,False,True,True,False]+[True,True]+[True,True]+>>> S.print $ mapped S.toList $ S.breaks id $ S.each [False,True,True,False,True,True,False]+[False]+[False]+[False]++-} breaks :: Monad m => (a -> Bool) -> Stream (Of a) m r -> Stream (Stream (Of a) m) m r@@ -520,9 +529,10 @@ if not (thus a) then Step $ fmap loop (yield a >> break thus p') else loop p'-{-#INLINABLE breaks #-}+{-# INLINABLE breaks #-} -{-| Apply an action to all values, re-yielding each+{-| Apply an action to all values, re-yielding each.+ The return value (@y@) of the function is ignored. >>> S.product $ S.chain Prelude.print $ S.each [1..5] 1@@ -531,15 +541,17 @@ 4 5 120 :> ()++See also 'mapM' for a variant of this which uses the return value of the function to transorm the values in the stream. -} -chain :: Monad m => (a -> m ()) -> Stream (Of a) m r -> Stream (Of a) m r+chain :: Monad m => (a -> m y) -> Stream (Of a) m r -> Stream (Of a) m r chain f = loop where loop str = case str of Return r -> return r Effect mn -> Effect (fmap loop mn) Step (a :> rest) -> Effect $ do- f a+ _ <- f a return (Step (a :> loop rest)) {-# INLINABLE chain #-} @@ -554,7 +566,7 @@ 'z' Note that it also has the effect of 'Data.Maybe.catMaybes', 'Data.Either.rights'- 'map snd' and such-like operations.+ @map snd@ and such-like operations. >>> S.print $ S.concat $ S.each [Just 1, Nothing, Just 2] 1@@ -616,7 +628,7 @@ cycle :: (Monad m, Functor f) => Stream f m r -> Stream f m s cycle str = loop where loop = str >> loop-{-#INLINABLE cycle #-}+{-# INLINABLE cycle #-} {-| Interpolate a delay of n seconds between yields.@@ -632,7 +644,7 @@ yield a liftIO $ threadDelay pico loop rest-{-#INLINABLE delay #-}+{-# INLINABLE delay #-} @@ -661,14 +673,14 @@ -} drained :: (Monad m, Monad (t m), MonadTrans t) => t m (Stream (Of a) m r) -> t m r drained tms = tms >>= lift . effects-{-#INLINE drained #-}+{-# INLINE drained #-} -- --------------- -- drop -- --------------- {-| Ignore the first n elements of a stream, but carry out the actions ->>> S.toList $ S.drop 2 $ S.replicateM 5 getLine+>>> S.toList $ S.drop 2 $ S.replicateM 5 getLine a<Enter> b<Enter> c<Enter>@@ -681,9 +693,6 @@ >>> S.toList $ concats $ maps (S.drop 4) $ chunksOf 5 $ each [1..20] [5,10,15,20] :> ()--- -} drop :: (Monad m) => Int -> Stream (Of a) m r -> Stream (Of a) m r@@ -767,8 +776,21 @@ Return r -> return r Effect m -> m >>= loop Step (_ :> rest) -> loop rest-{-#INLINABLE effects #-}+{-# INLINABLE effects #-} +{-| Before evaluating the monadic action returning the next step in the 'Stream', @wrapEffect@+ extracts the value in a monadic computation @m a@ and passes it to a computation @a -> m y@.++-}+wrapEffect :: (Monad m, Functor f) => m a -> (a -> m y) -> Stream f m r -> Stream f m r+wrapEffect m f = loop where+ loop stream = do+ x <- lift m+ step <- lift $ inspect stream+ _ <- lift $ f x+ either pure loop' step+ loop' stream = wrap (fmap loop stream)+ {-| Exhaust a stream remembering only whether @a@ was an element. -}@@ -783,7 +805,7 @@ if a == a' then fmap (True :>) (effects rest) else loop False rest-{-#INLINABLE elem #-}+{-# INLINABLE elem #-} elem_ :: (Monad m, Eq a) => a -> Stream (Of a) m r -> m Bool elem_ a' = loop False where@@ -795,7 +817,7 @@ if a == a' then return True else loop False rest-{-#INLINABLE elem_ #-}+{-# INLINABLE elem_ #-} -- ----- -- enumFrom@@ -803,8 +825,8 @@ {-| An infinite stream of enumerable values, starting from a given value. It is the same as @S.iterate succ@.- Because their return type is polymorphic, @enumFrom@ and @enumFromThen@- (and @iterate@ are useful for example with @zip@+ Because their return type is polymorphic, @enumFrom@, @enumFromThen@+ and @iterate@ are useful for example with @zip@ and @zipWith@, which require the same return type in the zipped streams. With @each [1..]@ the following bit of connect-and-resume would be impossible: @@ -870,7 +892,7 @@ else loop as {-# INLINE filter #-} -- ~ 10% faster than INLINABLE in simple bench - + -- --------------- -- filterM -- ---------------@@ -913,10 +935,10 @@ {- $folds Use these to fold the elements of a 'Stream'. ->>> S.fold_ (+) 0 id $ S.each [1..0]-50+>>> S.fold_ (+) 0 id $ S.each [1..10]+55 - The general folds 'fold', fold_', 'foldM' and 'foldM_' are arranged+ The general folds 'fold', 'fold_', 'foldM' and 'foldM_' are arranged for use with @Control.Foldl@ 'Control.Foldl.purely' and 'Control.Foldl.impurely' >>> L.purely fold_ L.sum $ each [1..10]@@ -924,8 +946,8 @@ >>> 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 an underscore omit- (e.g. @fold_@, @sum_@) the stream's return value in a left-strict pair.+ All functions marked with an underscore+ (e.g. @fold_@, @sum_@) omit the stream's return value in a left-strict pair. They are good for exiting streaming completely, but when you are, e.g. @mapped@-ing over a @Stream (Stream (Of a) m) m r@, which is to be compared with @[[a]]@. Specializing, we have e.g.@@ -962,7 +984,7 @@ -} fold_ :: Monad m => (x -> a -> x) -> x -> (x -> b) -> Stream (Of a) m r -> m b fold_ step begin done = fmap (\(a :> _) -> a) . fold step begin done-{-#INLINE fold_ #-}+{-# INLINE fold_ #-} {-| Strict fold of a 'Stream' of elements that preserves the return value. The third parameter will often be 'id' where a fold is written by hand:@@ -1006,7 +1028,7 @@ {-# INLINE fold #-} -{-| Strict, monadic fold of the elements of a 'Stream (Of a)'+{-| Strict, monadic fold of the elements of a @Stream (Of a)@ > Control.Foldl.impurely foldM :: Monad m => FoldM a b -> Stream (Of a) m () -> m b -}@@ -1014,16 +1036,16 @@ :: Monad m => (x -> a -> m x) -> m x -> (x -> m b) -> Stream (Of a) m r -> m b foldM_ step begin done = fmap (\(a :> _) -> a) . foldM step begin done-{-#INLINE foldM_ #-}+{-# INLINE foldM_ #-} -{-| Strict, monadic fold of the elements of a 'Stream (Of a)'+{-| Strict, monadic fold of the elements of a @Stream (Of a)@ > Control.Foldl.impurely foldM' :: Monad m => FoldM a b -> Stream (Of a) m r -> m (b, r) Thus to accumulate the elements of a stream as a vector, together with a random element we might write: ->>> L.impurely S.foldM (liftA2 (,) L.vector L.random) $ each [1..10::Int] :: IO (Of (U.Vector Int,Maybe Int) ())+>>> L.impurely S.foldM (liftA2 (,) L.vectorM L.random) $ each [1..10::Int] :: IO (Of (Vector Int, Maybe Int) ()) ([1,2,3,4,5,6,7,8,9,10],Just 9) :> () -}@@ -1055,7 +1077,7 @@ -- b <- done x' -- return (b :> r) -- where seq = Prelude.seq--- {-#INLINE foldM #-}+-- {-# INLINE foldM #-} {-| A natural right fold for consuming a stream of elements. See also the more general 'iterTM' in the 'Streaming' module@@ -1096,11 +1118,11 @@ -- | @for@ replaces each element of a stream with an associated stream. Note that the -- associated stream may layer any functor. for :: (Monad m, Functor f) => Stream (Of a) m r -> (a -> Stream f m x) -> Stream f m r-for str0 act = loop str0 where+for str0 f = loop str0 where loop str = case str of Return r -> Return r- Effect m -> Effect $ fmap loop m- Step (a :> rest) -> act a *> loop rest+ Effect m -> Effect $ fmap loop m+ Step (a :> as) -> f a *> loop as {-# INLINABLE for #-} -- -| Group layers of any functor by comparisons on a preliminary annotation@@ -1166,7 +1188,7 @@ -} group :: (Monad m, Eq a) => Stream (Of a) m r -> Stream (Stream (Of a) m) m r group = groupBy (==)-{-#INLINE group #-}+{-# INLINE group #-} head :: Monad m => Stream (Of a) m r -> m (Of (Maybe a) r)@@ -1174,15 +1196,26 @@ Return r -> return (Nothing :> r) Effect m -> m >>= head Step (a :> rest) -> effects rest >>= \r -> return (Just a :> r)-{-#INLINABLE head #-}+{-# INLINABLE head #-} head_ :: Monad m => Stream (Of a) m r -> m (Maybe a) head_ str = case str of Return _ -> return Nothing Effect m -> m >>= head_ Step (a :> _) -> return (Just a)-{-#INLINABLE head_ #-}+{-# INLINABLE head_ #-} ++{-| Intersperse given value between each element of the stream.++>>> S.print $ S.intersperse 0 $ each [1,2,3]+1+0+2+0+3++-} intersperse :: Monad m => a -> Stream (Of a) m r -> Stream (Of a) m r intersperse x str = case str of Return r -> Return r@@ -1193,7 +1226,7 @@ Return r -> Step (a :> Return r) Effect m -> Effect (fmap (loop a) m) Step (b :> rest) -> Step (a :> Step (x :> loop b rest))-{-#INLINABLE intersperse #-}+{-# INLINABLE intersperse #-} @@ -1230,7 +1263,7 @@ Just_ a -> return (Just a :> r) Effect m -> m >>= loop mb Step (a :> rest) -> loop (Just_ a) rest-{-#INLINABLE last #-}+{-# INLINABLE last #-} @@ -1242,7 +1275,7 @@ Just_ a -> return (Just a) Effect m -> m >>= loop mb Step (a :> rest) -> loop (Just_ a) rest-{-#INLINABLE last_ #-}+{-# INLINABLE last_ #-} -- ---------------@@ -1251,13 +1284,13 @@ {-| Run a stream, remembering only its length: ->>> S.length $ S.each [1..10]+>>> runIdentity $ S.length_ (S.each [1..10] :: Stream (Of Int) Identity ()) 10 -} length_ :: Monad m => Stream (Of a) m r -> m Int length_ = fold_ (\n _ -> n + 1) 0 id-{-#INLINE length_#-}+{-# INLINE length_ #-} {-| Run a stream, keeping its length and its return value. @@ -1271,7 +1304,7 @@ length :: Monad m => Stream (Of a) m r -> m (Of Int r) length = fold (\n _ -> n + 1) 0 id-{-#INLINE length #-}+{-# INLINE length #-} -- --------------- -- map -- ---------------@@ -1284,7 +1317,7 @@ -} map :: Monad m => (a -> b) -> Stream (Of a) m r -> Stream (Of b) m r-map f = maps (\(x :> rest) -> f x :> rest)+map f = maps (\(x :> rest) -> f x :> rest) -- loop where -- -- loop stream = case stream of -- Return r -> Return r@@ -1306,12 +1339,14 @@ 400 500 600++See also 'chain' for a variant of this which ignores the return value of the function and just uses the side effects. -} mapM :: Monad m => (a -> m b) -> Stream (Of a) m r -> Stream (Of b) m r mapM f = loop where loop str = case str of Return r -> Return r- Effect m -> Effect (fmap loop m)+ Effect m -> Effect (fmap loop m) Step (a :> as) -> Effect $ do a' <- f a return (Step (a' :> loop as) )@@ -1335,7 +1370,7 @@ 49 :> () -}-mapM_ :: Monad m => (a -> m b) -> Stream (Of a) m r -> m r+mapM_ :: Monad m => (a -> m x) -> Stream (Of a) m r -> m r mapM_ f = loop where loop str = case str of Return r -> return r@@ -1350,8 +1385,7 @@ > let noteBeginning text x = putStrLn text >> return text - this puts the- is completely functor-general+ this is completely functor-general @maps@ and @mapped@ obey these rules: @@ -1372,7 +1406,7 @@ mapped :: (Monad m, Functor f) => (forall x . f x -> m (g x)) -> Stream f m r -> Stream g m r mapped = mapsM-{-#INLINE mapped #-}+{-# INLINE mapped #-} {-| A version of 'mapped' that imposes a 'Functor' constraint on the target functor rather than the source functor. This version should be preferred if 'fmap' on the target@@ -1402,7 +1436,7 @@ {-| Fold streamed items into their monoidal sum ->>> S.mconcat $ S.take 2 $ S.map (Data.Monoid.Last . Just) (S.stdinLn)+>>> S.mconcat $ S.take 2 $ S.map (Data.Monoid.Last . Just) S.stdinLn first<Enter> last<Enter> Last {getLast = Just "last"} :> ()@@ -1426,19 +1460,19 @@ minimum_ = fold_ (\m a -> case m of Nothing_ -> Just_ a ; Just_ a' -> Just_ (min a a')) Nothing_ (\m -> case m of Nothing_ -> Nothing; Just_ r -> Just r)-{-#INLINE minimum_ #-}+{-# INLINE minimum_ #-} maximum :: (Monad m, Ord a) => Stream (Of a) m r -> m (Of (Maybe a) r) maximum = fold (\m a -> case m of Nothing_ -> Just_ a ; Just_ a' -> Just_ (max a a')) Nothing_ (\m -> case m of Nothing_ -> Nothing; Just_ r -> Just r)-{-#INLINE maximum #-}+{-# INLINE maximum #-} maximum_ :: (Monad m, Ord a) => Stream (Of a) m r -> m (Maybe a) maximum_ = fold_ (\m a -> case m of Nothing_ -> Just_ a ; Just_ a' -> Just_ (max a a')) Nothing_ (\m -> case m of Nothing_ -> Nothing; Just_ r -> Just r)-{-#INLINE maximum_ #-}+{-# INLINE maximum_ #-} {-| The standard way of inspecting the first item in a stream of elements, if the stream is still \'running\'. The @Right@ case contains a@@ -1446,7 +1480,7 @@ 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))+> 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))) Interoperate with @pipes@ producers thus:@@ -1457,7 +1491,7 @@ Similarly: > IOStreams.unfoldM (fmap (either (const Nothing) Just) . next) :: Stream (Of a) IO b -> IO (InputStream a)-> Conduit.unfoldM (fmap (either (const Nothing) Just) . next) :: Stream (Of a) m r -> Source a m r+> Conduit.unfoldM (fmap (either (const Nothing) Just) . next) :: Stream (Of a) m r -> Source a m r But see 'uncons', which is better fitted to these @unfoldM@s -}@@ -1484,7 +1518,7 @@ if a == a' then fmap (False :>) (effects rest) else loop True rest-{-#INLINABLE notElem #-}+{-# INLINABLE notElem #-} notElem_ :: (Monad m, Eq a) => a -> Stream (Of a) m r -> m Bool notElem_ a' = loop True where@@ -1496,13 +1530,13 @@ if a == a' then return False else loop True rest-{-#INLINABLE notElem_ #-}+{-# INLINABLE notElem_ #-} {-| Remove repeated elements from a Stream. 'nubOrd' of course accumulates a 'Data.Set.Set' of elements that have already been seen and should thus be used with care. ->>> S.toList_ $ S.nubOrd $ S.take 5 S.readLn :: IO ([Int])+>>> S.toList_ $ S.nubOrd $ S.take 5 S.readLn :: IO [Int] 1<Enter> 2<Enter> 3<Enter>@@ -1598,7 +1632,7 @@ {-| Fold a 'Stream' of numbers into their product with the return value -> maps' product' :: Stream (Stream (Of Int)) m r -> Stream (Of Int) m r+> mapped product :: Stream (Stream (Of Int)) m r -> Stream (Of Int) m r -} product :: (Monad m, Num a) => Stream (Of a) m r -> m (Of a r) product = fold (*) 1 id@@ -1643,7 +1677,7 @@ {-| Repeat a monadic action /ad inf./, streaming its results. ->>> S.toList $ S.take 2 $ repeatM getLine+>>> S.toList $ S.take 2 $ repeatM getLine one<Enter> two<Enter> ["one","two"]@@ -1701,7 +1735,7 @@ Just a -> return (Step (a :> loop)) {-# INLINABLE reread #-} -{-| Strict left scan, streaming, e.g. successive partial results. The seed +{-| Strict left scan, streaming, e.g. successive partial results. The seed is yielded first, before any action of finding the next element is performed. @@ -1723,34 +1757,34 @@ -} scan :: Monad m => (x -> a -> x) -> x -> (x -> b) -> Stream (Of a) m r -> Stream (Of b) m r scan step begin done str = Step (done begin :> loop begin str)- where - loop !acc stream = do+ where+ loop !acc stream = case stream of Return r -> Return r Effect m -> Effect (fmap (loop acc) m)- Step (a :> rest) -> - let !acc' = step acc a + Step (a :> rest) ->+ let !acc' = step acc a in Step (done acc' :> loop acc' rest)-{-#INLINABLE scan #-}+{-# INLINABLE scan #-} {-| Strict left scan, accepting a monadic function. It can be used with 'FoldM's from @Control.Foldl@ using 'impurely'. Here we yield a succession of vectors each recording ->>> let v = L.impurely scanM L.vector $ each [1..4::Int] :: Stream (Of (U.Vector Int)) IO ()+>>> let v = L.impurely scanM L.vectorM $ each [1..4::Int] :: Stream (Of (Vector Int)) IO () >>> S.print v-fromList []-fromList [1]-fromList [1,2]-fromList [1,2,3]-fromList [1,2,3,4]+[]+[1]+[1,2]+[1,2,3]+[1,2,3,4] -} scanM :: Monad m => (x -> a -> m x) -> m x -> (x -> m b) -> Stream (Of a) m r -> Stream (Of b) m r scanM step begin done str = Effect $ do x <- begin b <- done x- return (Step (b :> loop x str)) + return (Step (b :> loop x str)) where loop !x stream = case stream of -- note we have already yielded from x Return r -> Return r@@ -1765,8 +1799,7 @@ ) {-# INLINABLE scanM #-} -{- Label each element in a stream with a value accumulated according to a fold.-+{-| Label each element in a stream with a value accumulated according to a fold. >>> S.print $ S.scanned (*) 1 id $ S.each [100,200,300] (100,100)@@ -1780,16 +1813,14 @@ -} -data Maybe' a = Just' a | Nothing'- scanned :: Monad m => (x -> a -> x) -> x -> (x -> b) -> Stream (Of a) m r -> Stream (Of (a,b)) m r scanned step begin done = loop Nothing' begin where- loop !m !x stream = do+ loop !m !x stream = case stream of Return r -> return r Effect mn -> Effect $ fmap (loop m x) mn- Step (a :> rest) -> do+ Step (a :> rest) -> case m of Nothing' -> do let !acc = step x a@@ -1801,30 +1832,7 @@ loop (Just' a) (step x a) rest {-# INLINABLE scanned #-} --{-| Streams the number of seconds from the beginning of action-- Thus, to mark times of user input we might write something like:-->>> S.toList $ S.take 3 $ S.zip S.seconds S.stdinLn-a<Enter>-b<Enter>-c<Enter>-[(0.0,"a"),(1.088711,"b"),(3.7289649999999996,"c")] :> ()-- To restrict user input to some number of seconds, we might write:-->>> S.toList $ S.map fst $ S.zip S.stdinLn $ S.takeWhile (< 3) S.seconds-one<Enter>-two<Enter>-three<Enter>-four<Enter>-five<Enter>-["one","two","three","four","five"] :> ()-- This of course does not interrupt an action that has already begun.-- -}+data Maybe' a = Just' a | Nothing' -- --------------- -- sequence@@ -1875,15 +1883,16 @@ 55 :> () >>> (n :> rest) <- S.sum $ S.splitAt 3 $ each [1..10]->>> print n+>>> System.IO.print n 6 >>> (m :> rest') <- S.sum $ S.splitAt 3 rest->>> print m+>>> System.IO.print m 15 >>> S.print rest' 7 8 9+10 -} sum :: (Monad m, Num a) => Stream (Of a) m r -> m (Of a r)@@ -1926,7 +1935,7 @@ if a /= t then Step (fmap loop (yield a >> break (== t) rest)) else loop rest-{-#INLINABLE split #-}+{-# INLINABLE split #-} {-| Split a succession of layers after some number, returning a streaming or effectful pair. This function is the same as the 'splitsAt' exported by the@@ -1958,7 +1967,7 @@ Return r -> Return r Effect m -> Effect (fmap loop m) Step (a :> rest) -> Step (loop rest <$ f a)-{-#INLINABLE subst #-}+{-# INLINABLE subst #-} -- --------------- -- take -- ---------------@@ -1972,7 +1981,7 @@ >>> S.toList $ S.take 3 $ each "with" "wit" :> () ->>> runResourceT $ S.stdoutLn $ S.take 3 $ S.readFile "stream.hs"+>>> S.readFile "stream.hs" (S.stdoutLn . S.take 3) import Streaming import qualified Streaming.Prelude as S import Streaming.Prelude (each, next, yield)@@ -2030,7 +2039,7 @@ {-# INLINE takeWhileM #-} -{-| Convert an effectful 'Stream (Of a)' into a list of @as@+{-| Convert an effectful @Stream (Of a)@ into a list of @as@ Note: Needless to say, this function does not stream properly. It is basically the same as Prelude 'mapM' which, like 'replicateM',@@ -2045,22 +2054,23 @@ {-| Convert an effectful 'Stream' into a list alongside the return value -> mapped toList :: Stream (Stream (Of a)) m r -> Stream (Of [a]) m+> mapped toList :: Stream (Stream (Of a) m) m r -> Stream (Of [a]) m r - Like 'toList_', 'toList' breaks streaming; unlike 'toList_' it /preserves the return value/ + Like 'toList_', 'toList' breaks streaming; unlike 'toList_' it /preserves the return value/ and thus is frequently useful with e.g. 'mapped' >>> S.print $ mapped S.toList $ chunksOf 3 $ each [1..9] [1,2,3] [4,5,6] [7,8,9]+ >>> S.print $ mapped S.toList $ chunksOf 2 $ S.replicateM 4 getLine s<Enter> t<Enter> ["s","t"] u<Enter> v<Enter>-["u","v"] +["u","v"] -} toList :: Monad m => Stream (Of a) m r -> m (Of [a] r) toList = fold (\diff a ls -> diff (a: ls)) id (\diff -> diff [])@@ -2121,6 +2131,18 @@ {-# INLINABLE unfoldr #-} -- ---------------------------------------+-- untilLeft+-- ---------------------------------------+untilLeft :: Monad m => m (Either r a) -> Stream (Of a) m r+untilLeft act = Effect loop where+ loop = do+ e <- act+ case e of+ Right a -> return (Step (a :> Effect loop))+ Left r -> return (Return r)+{-# INLINABLE untilLeft #-}++-- --------------------------------------- -- untilRight -- --------------------------------------- untilRight :: Monad m => m (Either a r) -> Stream (Of a) m r@@ -2130,7 +2152,7 @@ case e of Right r -> return (Return r) Left a -> return (Step (a :> Effect loop))-{-#INLINABLE untilRight #-}+{-# INLINABLE untilRight #-} -- --------------------------------------- -- with@@ -2144,7 +2166,7 @@ > with = flip subst > subst = flip with ->>> with (each [1..3]) (yield . show) & intercalates (yield "--") & S.stdoutLn+>>> with (each [1..3]) (yield . Prelude.show) & intercalates (yield "--") & S.stdoutLn 1 -- 2@@ -2157,7 +2179,7 @@ Return r -> Return r Effect m -> Effect (fmap loop m) Step (a :> rest) -> Step (loop rest <$ f a)-{-#INLINABLE with #-}+{-# INLINABLE with #-} -- --------------------------------------- -- yield@@ -2169,7 +2191,7 @@ hello >>> S.sum $ do {yield 1; yield 2; yield 3}-6+6 :> () >>> let number = lift (putStrLn "Enter a number:") >> lift readLn >>= yield :: Stream (Of Int) IO () >>> S.toList $ do {number; number; number}@@ -2189,18 +2211,18 @@ -- | Zip two 'Stream's zip :: Monad m- => (Stream (Of a) m r)- -> (Stream (Of b) m r)- -> (Stream (Of (a,b)) m r)+ => Stream (Of a) m r+ -> Stream (Of b) m r+ -> Stream (Of (a,b)) m r zip = zipWith (,) {-# INLINE zip #-} -- | Zip two 'Stream's using the provided combining function zipWith :: Monad m => (a -> b -> c)- -> (Stream (Of a) m r)- -> (Stream (Of b) m r)- -> (Stream (Of c) m r)+ -> Stream (Of a) m r+ -> Stream (Of b) m r+ -> Stream (Of c) m r zipWith f = loop where loop str0 str1 = case str0 of@@ -2241,10 +2263,10 @@ -- | Zip three 'Stream's together zip3 :: Monad m- => (Stream (Of a) m r)- -> (Stream (Of b) m r)- -> (Stream (Of c) m r)- -> (Stream (Of (a,b,c)) m r)+ => Stream (Of a) m r+ -> Stream (Of b) m r+ -> Stream (Of c) m r+ -> Stream (Of (a,b,c)) m r zip3 = zipWith3 (,,) {-# INLINABLE zip3 #-} @@ -2292,7 +2314,7 @@ -} readLn :: (MonadIO m, Read a) => Stream (Of a) m ()-readLn = loop where +readLn = loop where loop = do eof <- liftIO IO.isEOF unless eof $ do@@ -2307,7 +2329,7 @@ Terminates on end of input ->>> IO.withFile "/usr/share/dict/words" IO.ReadMode $ S.stdoutLn . S.take 3 . S.drop 50000 . S.fromHandle+>>> IO.withFile "/usr/share/dict/words" IO.ReadMode $ S.stdoutLn . S.take 3 . S.drop 50000 . S.fromHandle deflagrator deflate deflation@@ -2348,7 +2370,6 @@ "hello" world<Enter> "world"->>> -} print :: (MonadIO m, Show a) => Stream (Of a) m r -> m r@@ -2406,7 +2427,7 @@ hello<Enter> world<Enter> ->>> S.stdoutLn $ S.readFile "lines.txt"+>>> S.readFile "lines.txt" S.stdoutLn hello world @@ -2431,106 +2452,33 @@ stdoutLn' :: MonadIO m => Stream (Of String) m r -> m r stdoutLn' = toHandle IO.stdout ---- -- * Producers--- -- $producers--- stdinLn ----- , readLn ----- , fromHandle ----- , repeatM ----- , replicateM -------- -- * Consumers--- -- $consumers--- , stdoutLn ----- , stdoutLn' ----- , mapM_ ----- , print ----- , toHandle ----- , effects -------- -- * Pipes--- -- $pipes--- , map ----- , mapM ----- , sequence ----- , mapFoldable ----- , filter ----- , filterM ----- , take ----- , takeWhile ----- , takeWhile' ----- , drop ----- , dropWhile ----- , concat ----- , elemIndices--- , findIndices--- , scan ----- , scanM ----- , chain ----- , read ----- , show ----- , seq -------- -- * Folds--- -- $folds--- , fold ----- , fold' ----- , foldM ----- , foldM' ----- , all--- , any--- , and--- , or--- , elem--- , notElem--- , find--- , findIndex--- , head--- , index--- , last--- , length--- , maximum--- , minimum--- , null--- , sum ----- , product ----- , toList ----- , toListM ----- , toListM' -------- -- * Zips--- , zip ----- , zipWith ------ distinguish :: (a -> Bool) -> Of a r -> Sum (Of a) (Of a) r distinguish predicate (a :> b) = if predicate a then InR (a :> b) else InL (a :> b)-{-#INLINE distinguish #-}+{-# INLINE distinguish #-} sumToEither ::Sum (Of a) (Of b) r -> Of (Either a b) r sumToEither s = case s of InL (a :> r) -> Left a :> r InR (b :> r) -> Right b :> r-{-#INLINE sumToEither #-}+{-# INLINE sumToEither #-} eitherToSum :: Of (Either a b) r -> Sum (Of a) (Of b) r eitherToSum s = case s of Left a :> r -> InL (a :> r) Right b :> r -> InR (b :> r)-{-#INLINE eitherToSum #-}+{-# INLINE eitherToSum #-} composeToSum :: Compose (Of Bool) f r -> Sum f f r composeToSum x = case x of Compose (True :> f) -> InR f Compose (False :> f) -> InL f-{-#INLINE composeToSum #-}+{-# INLINE composeToSum #-} sumToCompose :: Sum f f r -> Compose (Of Bool) f r sumToCompose x = case x of InR f -> Compose (True :> f) InL f -> Compose (False :> f)-{-#INLINE sumToCompose #-}+{-# INLINE sumToCompose #-} {-| Store the result of any suitable fold over a stream, keeping the stream for further manipulation. @store f = f . copy@ :@@ -2556,7 +2504,7 @@ simultaneously, and in constant memory -- as they would be if, say, you linked them together with @Control.Fold@: ->>> L.impurely S.foldM (liftA3 (\a b c -> (b,c)) (L.sink print) (L.generalize L.sum) (L.generalize L.product)) $ each [1..4]+>>> L.impurely S.foldM (liftA3 (\a b c -> (b, c)) (L.sink Prelude.print) (L.generalize L.sum) (L.generalize L.product)) $ each [1..4] 1 2 3@@ -2567,16 +2515,16 @@ than the corresponding succession of uses of 'store', but by constant factor that will be completely dwarfed when any IO is at issue. - But 'store' / 'copy' is /much/ more powerful, as you can see by reflecting on+ But 'store' \/ 'copy' is /much/ more powerful, as you can see by reflecting on uses like this: ->>> S.sum $ S.store (S.sum . mapped S.product . chunksOf 2) $ S.store (S.product . mapped S.sum . chunksOf 2 )$ each [1..6]+>>> S.sum $ S.store (S.sum . mapped S.product . chunksOf 2) $ S.store (S.product . mapped S.sum . chunksOf 2) $ each [1..6] 21 :> (44 :> (231 :> ())) It will be clear that this cannot be reproduced with any combination of lenses, @Control.Fold@ folds, or the like. (See also the discussion of 'copy'.) - It would conceivable be clearer to import a series of specializations of 'store'.+ It would conceivably be clearer to import a series of specializations of 'store'. It is intended to be used at types like these: > storeM :: (forall s m . Monad m => Stream (Of a) m s -> m (Of b s))@@ -2584,12 +2532,12 @@ > storeM = store > > storeMIO :: (forall s m . MonadIO m => Stream (Of a) m s -> m (Of b s))-> -> ( MonadIO n => Stream (Of a) n r -> Stream (Of a) n (Of b r)+> -> (MonadIO n => Stream (Of a) n r -> Stream (Of a) n (Of b r) > storeMIO = store It is clear from these types that we are just using the general instances: -> instance (Functor f, Monad m ) => Monad (Stream f m)+> instance (Functor f, Monad m) => Monad (Stream f m) > instance (Functor f, MonadIO m) => MonadIO (Stream f m) We thus can't be touching the elements of the stream, or the final return value.@@ -2597,7 +2545,7 @@ like 'MonadResource'. Thus I can independently filter and write to one file, but nub and write to another, or interact with a database and a logfile and the like: ->>> runResourceT $ (S.writeFile "hello2.txt" . S.nubOrd) $ store (S.writeFile "hello.txt" . S.filter (/= "world")) $ each ["hello", "world", "goodbye", "world"]+>>> (S.writeFile "hello2.txt" . S.nubOrd) $ store (S.writeFile "hello.txt" . S.filter (/= "world")) $ each ["hello", "world", "goodbye", "world"] >>> :! cat hello.txt hello goodbye@@ -2612,7 +2560,7 @@ :: Monad m => (Stream (Of a) (Stream (Of a) m) r -> t) -> Stream (Of a) m r -> t store f x = f (copy x)-{-#INLINE store #-}+{-# INLINE store #-} {-| Duplicate the content of stream, so that it can be acted on twice in different ways, but without breaking streaming. Thus, with @each [1,2]@ I might do:@@ -2627,10 +2575,10 @@ With copy, I can do these simultaneously: >>> S.print $ S.stdoutLn $ S.copy $ each ["one","two"]-one "one"-two+one "two"+two 'copy' should be understood together with 'effects' and is subject to the rules @@ -2656,7 +2604,7 @@ using 'Control.Foldl.handles' on an appropriate lens. Some such manipulations are simpler and more 'Data.List'-like, using 'copy': ->>> L.purely S.fold (liftA2 (,) (L.handles (filtered odd) L.sum) (L.handles (filtered even) L.product)) $ each [1..10]+>>> L.purely S.fold (liftA2 (,) (L.handles (L.filtered odd) L.sum) (L.handles (L.filtered even) L.product)) $ each [1..10] (25,3840) :> () becomes@@ -2703,13 +2651,15 @@ Return r -> Return r Effect m -> Effect (fmap loop (lift m)) Step (a :> rest) -> Effect (Step (a :> Return (Step (a :> loop rest))))-{-#INLINABLE copy#-}+{-# INLINABLE copy#-} +{-| An alias for @copy@.+-} duplicate :: Monad m => Stream (Of a) m r -> Stream (Of a) (Stream (Of a) m) r duplicate = copy-{-#INLINE duplicate #-}+{-# INLINE duplicate #-} {-| The type @@ -2725,7 +2675,7 @@ This @unzip@ does stream, though of course you can spoil this by using e.g. 'toList': ->>> let xs = map (\x-> (x,show x)) [1..5::Int]+>>> let xs = Prelude.map (\x -> (x, Prelude.show x)) [1..5 :: Int] >>> S.toList $ S.toList $ S.unzip (S.each xs) ["1","2","3","4","5"] :> ([1,2,3,4,5] :> ())@@ -2770,7 +2720,7 @@ Return r -> Return r Effect m -> Effect (fmap loop (lift m)) Step ((a,b):> rest) -> Step (a :> Effect (Step (b :> Return (loop rest))))-{-#INLINABLE unzip #-}+{-# INLINABLE unzip #-} @@ -2838,7 +2788,7 @@ LT -> Step (a :> loop rest0 str1) EQ -> Step (a :> loop rest0 str1) -- left-biased GT -> Step (b :> loop str0 rest1)-{-# INLINABLE mergeBy #-} +{-# INLINABLE mergeBy #-} {- $maybes These functions discard the 'Nothing's that they encounter. They are analogous@@ -2847,7 +2797,7 @@ {-| The 'catMaybes' function takes a 'Stream' of 'Maybe's and returns a 'Stream' of all of the 'Just' values. 'concat' has the same behavior,- but is more general; it works for any foldable container type. + but is more general; it works for any foldable container type. -} catMaybes :: Monad m => Stream (Of (Maybe a)) m r -> Stream (Of a) m r catMaybes = loop where@@ -2857,12 +2807,12 @@ Step (ma :> snext) -> case ma of Nothing -> loop snext Just a -> Step (a :> loop snext)-{-#INLINABLE catMaybes #-}+{-# INLINABLE catMaybes #-} {-| The 'mapMaybe' function is a version of 'map' which can throw out elements. In particular, the functional argument returns something of type @'Maybe' b@. If this is 'Nothing', no element is added on to the result 'Stream'. If it is @'Just' b@, then @b@ is included in the result 'Stream'.- + -} mapMaybe :: Monad m => (a -> Maybe b) -> Stream (Of a) m r -> Stream (Of b) m r mapMaybe phi = loop where@@ -2872,42 +2822,42 @@ Step (a :> snext) -> case phi a of Nothing -> loop snext Just b -> Step (b :> loop snext)-{-#INLINABLE mapMaybe #-}+{-# INLINABLE mapMaybe #-} -{-| 'slidingWindow' accumulates the first @n@ elements of a stream, +{-| 'slidingWindow' accumulates the first @n@ elements of a stream, update thereafter to form a sliding window of length @n@.- It follows the behavior of the slidingWindow function in + It follows the behavior of the slidingWindow function in <https://hackage.haskell.org/package/conduit-combinators-1.0.4/docs/Data-Conduit-Combinators.html#v:slidingWindow conduit-combinators>. ->>> S.print $ slidingWindow 4 $ S.each "123456"+>>> S.print $ S.slidingWindow 4 $ S.each "123456" fromList "1234" fromList "2345" fromList "3456" -} -slidingWindow :: Monad m - => Int - -> Stream (Of a) m b +slidingWindow :: Monad m+ => Int+ -> Stream (Of a) m b -> Stream (Of (Seq.Seq a)) m b-slidingWindow n = setup (max 1 n :: Int) mempty - where - window !sequ str = do - e <- lift (next str) - case e of +slidingWindow n = setup (max 1 n :: Int) mempty+ where+ window !sequ str = do+ e <- lift (next str)+ case e of Left r -> return r- Right (a,rest) -> do + Right (a,rest) -> do yield (sequ Seq.|> a) window (Seq.drop 1 $ sequ Seq.|> a) rest setup 0 !sequ str = do- yield sequ - window (Seq.drop 1 sequ) str - setup m sequ str = do - e <- lift $ next str - case e of + yield sequ+ window (Seq.drop 1 sequ) str+ setup m sequ str = do+ e <- lift $ next str+ case e of Left r -> yield sequ >> return r Right (x,rest) -> setup (m-1) (sequ Seq.|> x) rest-{-#INLINABLE slidingWindow #-}+{-# INLINABLE slidingWindow #-} -- | Map monadically over a stream, producing a new stream -- only containing the 'Just' values.@@ -2916,8 +2866,8 @@ loop stream = case stream of Return r -> Return r Effect m -> Effect (fmap loop m)- Step (a :> snext) -> Effect $ do+ Step (a :> snext) -> Effect $ flip fmap (phi a) $ \x -> case x of Nothing -> loop snext Just b -> Step (b :> loop snext)-{-#INLINABLE mapMaybeM #-}+{-# INLINABLE mapMaybeM #-}
streaming.cabal view
@@ -1,16 +1,16 @@ name: streaming-version: 0.2.2.0+version: 0.2.3.0 cabal-version: >=1.10 build-type: Simple synopsis: an elementary streaming prelude and general stream type. -description: This package contains two modules, <http://hackage.haskell.org/package/streaming/docs/Streaming.html Streaming> +description: This package contains two modules, <http://hackage.haskell.org/package/streaming/docs/Streaming.html Streaming> and <http://hackage.haskell.org/package/streaming/docs/Streaming-Prelude.html Streaming.Prelude>. The principal module, <http://hackage.haskell.org/package/streaming-0.1.4.3/docs/Streaming-Prelude.html 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 successive elements of type @a@ arise from some sort of monadic- action before the succession ends with a value of type @r@. + action before the succession ends with a value of type @r@. Everything in the library is organized to make programming with this type as simple as possible, by the simple expedient of making it as close to @Prelude@@@ -21,11 +21,11 @@ > 1<Enter> > 2<Enter> > 3<Enter>- > 6 :> () + > 6 :> () . sums the first three valid integers from user input. Similarly, .- > >>> S.stdoutLn $ S.map (map toUpper) $ S.take 2 S.stdinLn + > >>> S.stdoutLn $ S.map (map toUpper) $ S.take 2 S.stdinLn > hello<Enter> > HELLO > world!<Enter>@@ -33,13 +33,13 @@ . upper-cases the first two lines from stdin as they arise, and sends them to stdout. And so on,- with filtering, mapping, breaking, chunking, zipping, unzipping, replicating - and so forth: + with filtering, mapping, breaking, chunking, zipping, unzipping, replicating+ and so forth: we program with streams of @Int@s or @String@s directly as if they constituted something like a list. That's because streams really do constitute something- like a list, and the associated operations can mostly have the same names. - (A few, like @reverse@, don't stream and thus disappear; - others like @unzip@ are here given properly streaming formulation for the first time.) + like a list, and the associated operations can mostly have the same names.+ (A few, like @reverse@, don't stream and thus disappear;+ others like @unzip@ are here given properly streaming formulation for the first time.) And we everywhere oppose \"extracting a pure list from IO\", which is the origin of typical Haskell memory catastrophes.@@ -53,7 +53,7 @@ . > main = mapM newIORef [1..10^8::Int] >>= mapM readIORef >>= mapM_ print .- The new user notices that this exhausts memory, and worries about the efficiency of Haskell @IORefs@. + The new user notices that this exhausts memory, and worries about the efficiency of Haskell @IORefs@. But of course it exhausts memory! Look what it says! The problem is immediately cured by writing .@@ -100,7 +100,7 @@ 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 \'source\' or whatever- you call an effectful stream of items. + 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@@ -117,7 +117,7 @@ a complex framework, but in a way that integrates transparently with the rest of Haskell, using ideas - e.g. rank 2 types, which are here implicit or explicit in most mapping - that the user can carry elsewhere,- rather than chaining her understanding to the curiosities of + rather than chaining her understanding to the curiosities of a so-called streaming IO framework (as necessary as that is for certain purposes.) . See the@@ -186,12 +186,13 @@ license: BSD3 license-file: LICENSE author: michaelt-maintainer: andrew.thaddeus@gmail.com, what_is_it_to_do_anything@yahoo.com+maintainer: andrew.thaddeus@gmail.com, chessai1996@gmail.com stability: Experimental homepage: https://github.com/haskell-streaming/streaming bug-reports: https://github.com/haskell-streaming/streaming/issues category: Data, Pipes, Streaming extra-source-files: README.md, changelog.md+tested-with: GHC==7.10.3, GHC==8.0.2, GHC==8.2.2, GHC==8.4.4, GHC==8.6.2 source-repository head type: git@@ -203,24 +204,21 @@ , Streaming.Prelude , Streaming.Internal , Data.Functor.Of- other-extensions:- RankNTypes- , CPP- , StandaloneDeriving- , FlexibleContexts- , DeriveDataTypeable- , DeriveFoldable- , DeriveFunctor- , DeriveTraversable- , UndecidableInstances build-depends: base >=4.8 && <5 , mtl >=2.1 && <2.3 , mmorph >=1.0 && <1.2- , semigroups >= 0.18 && <0.19- , transformers >=0.5 && <0.6+ , transformers >=0.4 && <0.6 , transformers-base < 0.5 , ghc-prim , containers- hs-source-dirs: src- default-language: Haskell2010++ if !impl(ghc >= 8.0)+ build-depends:+ fail == 4.9.*+ , semigroups >= 0.18 && <0.20++ hs-source-dirs:+ src+ default-language:+ Haskell2010