packages feed

streaming 0.2.1.0 → 0.2.2.0

raw patch · 4 files changed

+225/−19 lines, 4 filesdep ~semigroupsnew-uploader

Dependency ranges changed: semigroups

Files

changelog.md view
@@ -1,3 +1,24 @@+- ???++    Added `nubOrd`, `nubInt`, `nubOrdOn`, `nubIntOn`.++    Fix performance regression in `for`.+    +    Add `foldMap` and `foldMap_`.+    +    Fix the behaviour of `slidingWindow 1`.+    +    Reintroduce `readFile` and `writeFile`, using plain `System.IO`+    instead of `ResourceT` machinery.++    Add `merge`, `mergeOn`, and `mergeBy`.++    Improve performance of `concat`.++    Improve performance of (`*>`), getting rid of the default implementation.++    Generalise type signature of `toList_`.+ - 0.2.1.0      Adding `Semigroup` instances for GHC 8.4.
src/Streaming/Internal.hs view
@@ -231,12 +231,8 @@ instance (Functor f, Monad m) => Monad (Stream f m) where   return = Return   {-# INLINE return #-}-  stream1 >> stream2 = loop stream1 where-    loop stream = case stream of-      Return _ -> stream2-      Effect m  -> Effect (fmap loop m)-      Step f   -> Step (fmap loop f)  -  {-# INLINABLE (>>) #-}+  (>>) = (*>)+  {-# INLINE (>>) #-}   -- (>>=) = _bind   -- {-#INLINE (>>=) #-}   --@@ -281,6 +277,13 @@   {-# INLINE pure #-}   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)+      Step f   -> Step (fmap loop f)+  {-# INLINABLE (*>) #-}+  {- | The 'Alternative' instance glues streams together stepwise. 
src/Streaming/Prelude.hs view
@@ -70,6 +70,7 @@     , stdinLn     , readLn     , fromHandle+    , readFile      , iterate     , iterateM     , repeat@@ -91,6 +92,7 @@     , mapM_     , print     , toHandle+    , writeFile      , effects     , erase     , drained@@ -112,6 +114,10 @@     , store     , chain     , sequence+    , nubOrd+    , nubOrdOn+    , nubInt+    , nubIntOn     , filter     , filterM     , mapMaybeM@@ -166,6 +172,8 @@     , fold_     , foldM     , foldM_+    , foldMap+    , foldMap_     , all     , all_     , any@@ -221,6 +229,13 @@     , partitionEithers     , partition +    -- * Merging streams+    -- $merging++    , merge+    , mergeOn+    , mergeBy+         -- * Maybes     -- $maybes     , catMaybes@@ -260,7 +275,7 @@                       , print, zipWith, zip, zipWith3, zip3, unzip, seq, show, read                       , readLn, sequence, concat, span, break, readFile, writeFile                       , minimum, maximum, elem, notElem, all, any, head-                      , last)+                      , last, foldMap)  import qualified GHC.IO.Exception as G import qualified System.IO as IO@@ -270,6 +285,9 @@ 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)  -- instance (Eq a) => Eq1 (Of a) where eq1 = (==) -- instance (Ord a) => Ord1 (Of a) where compare1 = compare@@ -525,7 +543,7 @@       return (Step (a :> loop rest)) {-# INLINABLE chain #-} -{-| Make a stream of traversable containers into a stream of their separate elements.+{-| Make a stream of foldable containers into a stream of their separate elements.     This is just  > concat str = for str each@@ -551,8 +569,18 @@ -}  concat :: (Monad m, Foldable.Foldable f) => Stream (Of (f a)) m r -> Stream (Of a) m r-concat str = for str each-{-# INLINE concat #-}+concat = loop+  where+    loop str = case str of+        Return r -> Return r+        Effect m -> Effect (fmap loop m)+        Step (lst :> as) ->+          let inner [] = loop as+              inner (x:rest) = Step (x :> inner rest)+          in inner (Foldable.toList lst)+{-# INLINABLE concat #-}+-- The above hand-written loop is ~20% faster than the 'for' implementation+-- concat str = for str each  {-| The natural @cons@ for a @Stream (Of a)@. @@ -1355,6 +1383,23 @@ mappedPost = mapsMPost {-# INLINE mappedPost #-} +{-| Map each element of the stream to a monoid, and take the monoidal sum of the results.++>>> S.foldMap Sum $ S.take 2 (S.stdinLn)+1<Enter>+2<Enter>+3<Enter>+Sum {getSum = 6} :> ()++ -}+foldMap :: (Monad m, Monoid w) => (a -> w) -> Stream (Of a) m r -> m (Of w r)+foldMap f = fold (\ !acc a -> mappend acc (f a)) mempty id+{-# INLINE foldMap #-}++foldMap_ :: (Monad m, Monoid w) => (a -> w) -> Stream (Of a) m r -> m w+foldMap_ f = fold_ (\ !acc a -> mappend acc (f a)) mempty id+{-# INLINE foldMap_ #-}+ {-| Fold streamed items into their monoidal sum  >>> S.mconcat $ S.take 2 $ S.map (Data.Monoid.Last . Just) (S.stdinLn)@@ -1365,7 +1410,7 @@  -} mconcat :: (Monad m, Monoid w) => Stream (Of w) m r -> m (Of w r) mconcat = fold mappend mempty id-{-#INLINE mconcat #-}+{-# INLINE mconcat #-}  data Maybe_ a = Just_ !a | Nothing_ mconcat_ :: (Monad m, Monoid w) => Stream (Of w) m r -> m w@@ -1375,7 +1420,7 @@ 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 #-}  minimum_ :: (Monad m, Ord a) => Stream (Of a) m r -> m (Maybe a) minimum_ = fold_ (\m a -> case m of Nothing_ -> Just_ a ; Just_ a' -> Just_ (min a a'))@@ -1454,6 +1499,51 @@ {-#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])+1<Enter>+2<Enter>+3<Enter>+1<Enter>+2<Enter>+[1,2,3]++-}++nubOrd :: (Monad m, Ord a) => Stream (Of a) m r -> Stream (Of a) m r+nubOrd = nubOrdOn id+{-# INLINE nubOrd #-}++{-|  Use 'nubOrdOn' to have a custom ordering function for your elements. -}+nubOrdOn :: (Monad m, Ord b) => (a -> b) -> Stream (Of a) m r -> Stream (Of a) m r+nubOrdOn f xs = loop mempty xs where+  loop !set stream = case stream of+    Return r         -> Return r+    Effect m         -> Effect (liftM (loop set) m)+    Step (a :> rest) -> let !fa = f a in+      if Set.member fa set+         then loop set rest+         else Step (a :> loop (Set.insert fa set) rest)++{-| More efficient versions of above when working with 'Int's that use 'Data.IntSet.IntSet'. -}++nubInt :: Monad m => Stream (Of Int) m r -> Stream (Of Int) m r+nubInt = nubIntOn id+{-# INLINE nubInt #-}++nubIntOn :: Monad m => (a -> Int) -> Stream (Of a) m r -> Stream (Of a) m r+nubIntOn f xs = loop mempty xs where+  loop !set stream = case stream of+    Return r         -> Return r+    Effect m         -> Effect (liftM (loop set) m)+    Step (a :> rest) -> let !fa = f a in+      if IntSet.member fa set+         then loop set rest+         else Step (a :> loop (IntSet.insert fa set) rest)++ {-| > filter p = hoist effects (partition p) @@ -1948,7 +2038,7 @@     is a leading cause of space leaks.  -}-toList_ :: Monad m => Stream (Of a) m () -> m [a]+toList_ :: Monad m => Stream (Of a) m r -> m [a] toList_ = fold_ (\diff a ls -> diff (a: ls)) id (\diff -> diff []) {-# INLINE toList_ #-} @@ -2097,7 +2187,7 @@ yield a = Step (a :> Return ()) {-# INLINE yield #-} --- | Zip two 'Streams's+-- | Zip two 'Stream's zip :: Monad m     => (Stream (Of a) m r)     -> (Stream (Of b) m r)@@ -2105,7 +2195,7 @@ zip = zipWith (,) {-# INLINE zip #-} --- | Zip two 'Streams's using the provided combining function+-- | Zip two 'Stream's using the provided combining function zipWith :: Monad m     => (a -> b -> c)     -> (Stream (Of a) m r)@@ -2149,7 +2239,7 @@ {-# INLINABLE zipWith3 #-}  --- | Zip three streams together+-- | Zip three 'Stream's together zip3 :: Monad m     => (Stream (Of a) m r)     -> (Stream (Of b) m r)@@ -2296,8 +2386,34 @@            Right () -> loop rest {-# INLINABLE stdoutLn #-} +{-| Read the lines of a file, using a function of the type: \'@'Stream' ('Of' 'String') 'IO' () -> 'IO' a@\'+    to turn the stream into a value of type \''IO' a\'. +>>> S.writeFile "lines.txt" $ S.take 2 S.stdinLn+hello<Enter>+world<Enter>+>>> S.readFile "lines.txt" S.print+"hello"+"world" +-}+readFile :: FilePath -> (Stream (Of String) IO () -> IO a) -> IO a+readFile f s = IO.withFile f IO.ReadMode $ \h -> s (fromHandle h)++{-| Write a series of 'String's as lines to a file.++>>> S.writeFile "lines.txt" $ S.take 2 S.stdinLn+hello<Enter>+world<Enter>++>>> S.stdoutLn $ S.readFile "lines.txt"+hello+world++-}+writeFile :: FilePath -> Stream (Of String) IO r -> IO r+writeFile f = IO.withFile f IO.WriteMode . flip toHandle+ {-| Write 'String's to 'IO.stdout' using 'putStrLn'      Unlike @stdoutLn@, @stdoutLn'@ does not handle a broken output pipe. Thus it can have a polymorphic return@@ -2481,7 +2597,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.nub) $ store (S.writeFile "hello.txt" . S.filter (/= "world")) $ each ["hello", "world", "goodbye", "world"]+>>> runResourceT $ (S.writeFile "hello2.txt" . S.nubOrd) $ store (S.writeFile "hello.txt" . S.filter (/= "world")) $ each ["hello", "world", "goodbye", "world"] >>> :! cat hello.txt hello goodbye@@ -2658,6 +2774,72 @@   +{- $merging+   These functions combine two sorted streams of orderable elements+   into one sorted stream. The elements of the merged stream are+   guaranteed to be in a sorted order if the two input streams are+   also sorted.++   The merge operation is /left-biased/: when merging two elements+   that compare as equal, the left element is chosen first.+-}++{- | Merge two streams of elements ordered with their 'Ord' instance.++   The return values of both streams are returned.++>>> S.print $ merge (each [1,3,5]) (each [2,4])+1+2+3+4+5+((), ())++-}+merge :: (Monad m, Ord a)+  => Stream (Of a) m r+  -> Stream (Of a) m s+  -> Stream (Of a) m (r, s)+merge = mergeBy compare+{-# INLINE merge #-}++{- | Merge two streams, ordering them by applying the given function to+   each element before comparing.++   The return values of both streams are returned.+-}+mergeOn :: (Monad m, Ord b)+  => (a -> b)+  -> Stream (Of a) m r+  -> Stream (Of a) m s+  -> Stream (Of a) m (r, s)+mergeOn f = mergeBy (comparing f)+{-# INLINE mergeOn #-}++{- | Merge two streams, ordering the elements using the given comparison function.++   The return values of both streams are returned.+-}+mergeBy :: Monad m+  => (a -> a -> Ordering)+  -> Stream (Of a) m r+  -> Stream (Of a) m s+  -> Stream (Of a) m (r, s)+mergeBy cmp = loop+  where+    loop str0 str1 = case str0 of+      Return r0         -> (\ r1 -> (r0, r1)) <$> str1+      Effect m          -> Effect $ fmap (\ str -> loop str str1) m+      Step (a :> rest0) -> case str1 of+        Return r1         -> (\ r0 -> (r0, r1)) <$> str0+        Effect m          -> Effect $ fmap (loop str0) m+        Step (b :> rest1) -> case cmp a b of+          LT -> Step (a :> loop rest0 str1)+          EQ -> Step (a :> loop rest0 str1) -- left-biased+          GT -> Step (b :> loop str0 rest1)+{-# INLINABLE mergeBy #-}        + {- $maybes     These functions discard the 'Nothing's that they encounter. They are analogous     to the functions from @Data.Maybe@ that share their names.@@ -2716,7 +2898,7 @@         Left r -> return r         Right (a,rest) -> do            yield (sequ Seq.|> a)-          window (Seq.drop 1 sequ Seq.|> a) rest+          window (Seq.drop 1 $ sequ Seq.|> a) rest     setup 0 !sequ str = do        yield sequ         window (Seq.drop 1 sequ) str 
streaming.cabal view
@@ -1,5 +1,5 @@ name:                streaming-version:             0.2.1.0+version:             0.2.2.0 cabal-version:       >=1.10 build-type:          Simple synopsis:            an elementary streaming prelude and general stream type.