pipes 4.0.1 → 4.0.2
raw patch · 5 files changed
+113/−30 lines, 5 filesdep ~criterion
Dependency ranges changed: criterion
Files
- pipes.cabal +3/−3
- src/Pipes.hs +14/−7
- src/Pipes/Core.hs +11/−3
- src/Pipes/Prelude.hs +8/−7
- src/Pipes/Tutorial.hs +77/−10
pipes.cabal view
@@ -1,5 +1,5 @@ Name: pipes-Version: 4.0.1+Version: 4.0.2 Cabal-Version: >= 1.10 Build-Type: Simple License: BSD3@@ -77,7 +77,7 @@ Build-Depends: base >= 4 && < 5 ,- criterion >= 0.8 && < 0.9,+ criterion >= 0.6.2.1 && < 0.9, mtl >= 2.0.1.0 && < 2.2, pipes >= 4.0.0 && < 4.1 @@ -106,7 +106,7 @@ Build-Depends: base >= 4 && < 5 ,- criterion >= 0.8 && < 0.9,+ criterion >= 0.6.2.1 && < 0.9, deepseq , mtl >= 2.0.1.0 && < 2.2, pipes >= 4.0.0 && < 4.1,
src/Pipes.hs view
@@ -71,11 +71,11 @@ import Control.Applicative (Applicative(pure, (<*>)), Alternative(empty, (<|>))) import Control.Monad (MonadPlus(mzero, mplus))-import Control.Monad.IO.Class (MonadIO(liftIO)) -- transformers-import Control.Monad.Trans.Class (MonadTrans(lift)) --transformers+import Control.Monad.IO.Class (MonadIO(liftIO))+import Control.Monad.Trans.Class (MonadTrans(lift)) import Control.Monad.Trans.Error (ErrorT(runErrorT))-import Control.Monad.Trans.Identity (IdentityT(runIdentityT)) --transformers-import Control.Monad.Trans.Maybe (MaybeT(runMaybeT)) --transformers+import Control.Monad.Trans.Identity (IdentityT(runIdentityT))+import Control.Monad.Trans.Maybe (MaybeT(runMaybeT)) import Data.Foldable (Foldable) import qualified Data.Foldable as F import Data.Monoid (Monoid(..))@@ -470,10 +470,17 @@ {-# INLINABLE next #-} -- | Convert a 'F.Foldable' to a 'Producer'-each :: (Monad m, F.Foldable f) => f a -> Producer' a m ()-each = F.mapM_ yield+each :: (Monad m, Foldable f) => f a -> Producer' a m ()+each = F.foldr (\a p -> yield a >> p) (return ()) {-# INLINABLE each #-}+{- The above code is the same as: +> each = Data.Foldable.mapM_ yield++ ... except writing it directly in terms of `Data.Foldable.foldr` improves+ build/foldr fusion+-}+ -- | Convert an 'Enumerable' to a 'Producer' every :: (Monad m, Enumerable t) => t m a -> Producer' a m () every it = discard >\\ enumerate (toListT it)@@ -506,5 +513,5 @@ #endif "Data.Foldable" re-exports 'Foldable' (the class name only) - "Data.Void" re-exports 'Void'.+ "Data.Void" re-exports 'Void' -}
src/Pipes/Core.hs view
@@ -81,9 +81,13 @@ , (<\\) , (//<) , (<<+)++ -- * Re-exports+ , module Data.Void ) where -import Data.Void (Void, absurd)+import Data.Void (Void)+import qualified Data.Void as V import Pipes.Internal (Proxy(..)) {- $proxy@@ -121,8 +125,8 @@ runEffect = go where go p = case p of- Request v _ -> absurd v- Respond v _ -> absurd v+ Request v _ -> V.absurd v+ Respond v _ -> V.absurd v M m -> m >>= go Pure r -> return r {-# INLINABLE runEffect #-}@@ -842,3 +846,7 @@ ; "f >\\ request x" forall f x . f >\\ request x = f x #-}++{- $reexports+ @Data.Void@ re-exports the 'Void' type+-}
src/Pipes/Prelude.hs view
@@ -11,8 +11,9 @@ dependency on the @text@ package. Also, 'stdinLn' and 'stdoutLn' remove and add newlines, respectively. This- behavior is intended to simplify examples. The upcoming 'ByteString' and- 'Text' utilities for @pipes@ will preserve newlines.+ behavior is intended to simplify examples. The corresponding @stdin@ and+ @stdout@ utilities from @pipes-bytestring@ and @pipes-text@ preserve+ newlines. -} {-# LANGUAGE RankNTypes, CPP #-}@@ -98,14 +99,14 @@ import Foreign.C.Error (Errno(Errno), ePIPE) import qualified GHC.IO.Exception as G import Pipes+import Pipes.Core import Pipes.Internal import qualified System.IO as IO-import qualified Prelude #ifndef haskell98 import Control.Monad.Trans.State.Strict (get, put)-import Pipes.Core import Pipes.Lift (evalStateP) #endif+import qualified Prelude import Prelude hiding ( all , and@@ -548,9 +549,9 @@ head :: (Monad m) => Producer a m () -> m (Maybe a) head p = do x <- next p- case x of- Left _ -> return Nothing- Right (a, _) -> return (Just a)+ return $ case x of+ Left _ -> Nothing+ Right (a, _) -> Just a {-# INLINABLE head #-} -- | Index into a 'Producer'
src/Pipes/Tutorial.hs view
@@ -80,6 +80,9 @@ -- * Appendix: Types -- $types++ -- * Appendix: Time Complexity+ -- $timecomplexity ) where import Control.Category@@ -1358,27 +1361,46 @@ However, polymorphic type synonyms cause problems in many other cases: - * They induce higher-rank types and require you to enable the @RankNTypes@- extension to use them in your own type signatures.-- * They give the wrong behavior when used in the negative position of a- function like this:+ * They usually give the wrong behavior when used as the argument of a+ function (known as the \"negative\" or \"contravariant\" position) like+ this: > f :: Producer' a m r -> ... -- Wrong > > f :: Producer a m r -> ... -- Right - * You can't use them within other types without the @ImpredicativeTypes@- extension:+ The former function only accepts polymorphic 'Producer's as arguments.+ The latter function accepts both polymorphic and concrete 'Producer's,+ which is probably what you want. -> io :: IO (Producer' a m r) -- Type error+ * Even when you desire a polymorphic argument, this induces a higher-ranked+ type, because it translates to a @forall@ which you cannot factor out to+ the top-level to simplify the type signature: - * You can't partially apply them:+> f :: (forall x' x y' . Proxy x' x y' m r) -> ... + These kinds of type signatures require the @RankNTypes@ extension.++ * Even when you have polymorphic type synonyms as the result of a function+ (i.e. the \"positive\" or \"covariant\" position), recent versions of+ @ghc@ such still require the @RankNTypes@ extension. For example, the+ 'Pipes.Prelude.fromHandle' function from "Pipes.Prelude" requires+ @RankNTypes@ to compile correctly on @ghc-7.6.3@:++> fromHandle :: (MonadIO m) => Handle -> Producer' String m ()++ * You can't use polymorphic type synonyms inside other type constructors+ without the @ImpredicativeTypes@ extension:++> io :: IO (Producer' a m r) -- Type error without ImpredicativeTypes++ * You can't partially apply polymorphic type synonyms:+ > stack :: MaybeT (Producer' a m) r -- Type error In these scenarios you should fall back on the concrete type synonyms, which- are better behaved.+ are better behaved. If concrete type synonyms are unsatisfactory, then ask+ @ghc@ to infer the most general type signature and use that. For the purposes of debugging type errors you can just remember that: @@ -1438,4 +1460,49 @@ > type Server' b' b m r = forall x' x . Proxy x' x b' b m r > type Client' a' a m r = forall y' y . Proxy a' a y' y m r +-}++{- $timecomplexity+ There are three functions that give quadratic time complexity when used in+ within @pipes@:++ * 'sequence'++ * 'replicateM'++ * 'mapM'++ For example, the time complexity of this code segment scales quadratically+ with `n`:++> import Control.Monad (replicateM)+> import Pipes+>+> quadratic :: Int -> Consumer a m [a]+> quadratic n = replicateM n await++ These three functions are generally bad practice to use, because all three+ of them correspond to \"ListT done wrong\", building a list in memory+ instead of streaming results.++ However, sometimes situations arise where one deliberately intends to build+ a list in memory. The solution is to use the \"codensity transformation\"+ to transform the code to run with linear time complexity. This involves:++ * wrapping the code in the @Codensity@ monad transformer (from+ @Control.Monad.Codensity@ module of the @kan-extensions@ package) using+ 'lift'++ * applying 'sequence' \/ 'replicateM' \/ 'mapM'++ * unwrapping the code using @lowerCodensity@++ To illustrate this, we'd transform the above example to:++> import Control.Monad.Codensity (lowerCodensity)+> +> linear :: (Monad m) => Int -> Consumer a m [a]+> linear n = lowerCodensity $ replicateM n $ lift await++ This will produce the exact same result, but in linear time. -}