packages feed

pipes 3.0.0 → 3.1.0

raw patch · 14 files changed

+264/−179 lines, 14 filesdep ~base

Dependency ranges changed: base

Files

Control/MFunctor.hs view
@@ -5,7 +5,9 @@ module Control.MFunctor (     -- * Functors over Monads     MFunctor(..),-    raise+    hoistK,+    raise,+    raiseK     ) where  import Control.Monad.Trans.Class (MonadTrans(lift))@@ -18,11 +20,26 @@ import qualified Control.Monad.Trans.Writer.Strict as WriterStrict import qualified Control.Monad.Trans.Writer.Lazy   as WriterLazy --- | A functor in the category of monads+{- | A functor in the category of monads++> hoist f . hoist g = hoist (f . g)+>+> hoist id = id++    If @f@ is a monad morphism, then @hoist f@ is a monad morphism, meaning that+    @hoistK f = (hoist f .)@ defines a functor between Kleisli categories:++> hoistK f k1 >=> hoistK f k2 = hoistK f (k1 >=> k2)+>+> hoistK f return = return+-} class MFunctor t where     {-| Lift a monad morphism from @m@ to @n@ into a monad morphism from         @(t m)@ to @(t n)@ -}-    hoist :: (Monad m) => (forall a . m a -> n a) -> t m b -> t n b+    hoist+     :: (Monad m)+     => (forall a . m a -> n a)  -- ^ Monad morphism+     -> t m b -> t n b  instance MFunctor IdentityT where     hoist nat = mapIdentityT nat@@ -48,9 +65,26 @@ instance MFunctor (WriterLazy.WriterT w) where     hoist nat = WriterLazy.mapWriterT nat +-- | Convenience function equivalent to @(hoist f .)@+hoistK+ :: (Monad m, MFunctor t)+ => (forall a . m a -> n a)  -- ^ Monad morphism+ -> (b' -> t m b)            -- ^ Kleisli arrow+ -> (b' -> t n b)+hoistK k p a' = hoist k (p a')+-- hoistK k = (hoist k .)+ {-| Lift the base monad  > raise = hoist lift -} raise :: (Monad m, MFunctor t1, MonadTrans t2) => t1 m r -> t1 (t2 m) r raise = hoist lift++{-| Lift the base monad of a \'@K@\'leisli arrow++> raiseK = hoistK lift+-}+raiseK+ :: (Monad m, MFunctor t1, MonadTrans t2) => (q -> t1 m r) -> (q -> t1 (t2 m) r)+raiseK = (hoist lift .)
Control/PFunctor.hs view
@@ -5,28 +5,85 @@ module Control.PFunctor (     -- * Functors over Proxies     PFunctor(..),-    raiseP+    hoistPK,+    raiseP,+    raisePK,     ) where  import Control.Proxy.Class (Proxy) import Control.Proxy.Trans (ProxyTrans(liftP)) --- | A functor in the category of monads-class PFunctor (-    t :: (* -> * -> * -> * -> (* -> *) -> * -> *)-      ->  * -> * -> * -> * -> (* -> *) -> * -> * ) where-    {-| Lift a proxy morphism from @p@ to @q@ into a proxy morphism from-        @(t p)@ to @(t q)@ -}+{-| A functor in the category of proxies++> hoistP f . hoistP g = hoistP (f . g)+>+> hoistP id = id++    If @f@ is a proxy morphism, then @hoistP f@ is a proxy morphism, meaning+    that @hoistPK f = (hoistP f .)@ defines a functor between five categories.++    Functor between Kleisli categories:++> hoistPK f p1 >=> hoistPK f p2 = hoistPK f (p1 >=> p2)+>+> hoistPK f return = return++    Functor between 'P.Proxy' categories:++> hoistPK f p1 >-> hoistPK f p2 = hoistPK f (p1 >-> p2)+>+> hoistPK f idT = idT++> hoistPK f p1 >~> hoistPK f p2 = hoistPK f (p1 >~> p2)+>+> hoistPK f coidT = coidT++    Functor between \"request\" categories:++> hoistPK f p1 \>\ hoistPK f p2 = hoistPK f (p2 \>\ p2)+>+> hoistPK f request = request++    Functor between \"respond\" categories:++> hoistPK f p1 />/ hoistPK f p2 = hoistPK f (p2 />/ p2)+>+> hoistPK f respond = respond+-}+class PFunctor (t+    :: (* -> * -> * -> * -> (* -> *) -> * -> *)+    ->  * -> * -> * -> * -> (* -> *) -> * -> * ) where+    {-| Lift a proxy morphism from @p1@ to @p2@ into a proxy morphism from+        @(t p1)@ to @(t p2)@ -}     hoistP-     :: (Monad m, Proxy p)-     => (forall a' a b' b r1 . p a' a b' b m r1 -> q a' a b' b m r1)-     -> (t p a' a b' b m r2 -> t q a' a b' b m r2)+     :: (Monad m, Proxy p1)+     => (forall r1 . p1 a' a b' b m r1 ->   p2 a' a b' b n r1) -- ^ Proxy morphism+     -> (          t p1 a' a b' b m r2 -> t p2 a' a b' b n r2) +-- | Convenience function equivalent to @(hoistP f .)@+hoistPK+ :: (Monad m, Proxy p1, PFunctor t)+ => (forall r1 . p1 a' a b' b m r1 -> p2 a' a b' b n r1) -- ^ Proxy morphism+ -> (q -> t p1 a' a b' b m r2) -- ^ Proxy Kleisli arrow+ -> (q -> t p2 a' a b' b n r2)+hoistPK f = (hoistP f .)+ {-| Lift the base proxy  > raiseP = hoistP liftP -} raiseP  :: (Monad m, Proxy p, PFunctor t1, ProxyTrans t2)- => t1 p a' a b' b m r -> t1 (t2 p) a' a b' b m r+ => t1 p a' a b' b m r -- ^ Proxy+ -> t1 (t2 p) a' a b' b m r raiseP = hoistP liftP++{-| Lift the base proxy of a \'@K@\'leisli arrow++> raisePK = hoistPK liftP+-}+raisePK+ :: (Monad m, Proxy p, PFunctor t1, ProxyTrans t2)+ => (q -> t1 p a' a b' b m r) -- ^ Proxy Kleisli arrow+ -> (q -> t1 (t2 p) a' a b' b m r)+raisePK = hoistPK liftP
Control/Proxy/Class.hs view
@@ -1,5 +1,3 @@-{-# LANGUAGE Rank2Types #-}- {-| The 'Proxy' class defines the library's core API.  Everything else in this     library builds exclusively on top of the 'Proxy' type class so that all     proxy implementations and extensions can share the same standard library.@@ -9,6 +7,8 @@     duplicate methods.  Instead, read the \"Polymorphic proxies\" section below     which explains their purpose and how they help clean up type signatures. -} +{-# LANGUAGE Rank2Types #-}+ module Control.Proxy.Class (     -- * Core proxy class     Proxy(..),@@ -258,18 +258,6 @@ > p >~> coidT = p > > (p1 >~> p2) >~> p3 = p1 >~> (p2 >~> p3)--    * @(hoistK f)@ defines a functor between proxy categories:--> Define: hoistK f = (hoist f .)->-> hoistK f (p1 >-> p2) = hoistK f p1 >-> hoistK p2->-> hoistK f idT = idT->-> hoistK f (p1 >~> p2) = hoistK f p1 >~> hoistK p2->-> hoistK f coidT = coidT      Also, all proxies must satisfy the following 'Proxy' laws: 
Control/Proxy/Core.hs view
@@ -10,10 +10,11 @@     module Control.Proxy.Trans.Identity,     module Control.Monad,     module Control.Monad.Trans.Class,-    module Control.MFunctor+    module Control.MFunctor,+    module Control.PFunctor     ) where -import Control.MFunctor (MFunctor(hoist))+import Control.MFunctor import Control.Monad (forever, (>=>), (<=<)) import Control.Monad.Trans.Class (MonadTrans(lift)) import Control.Proxy.Class@@ -21,6 +22,7 @@ import Control.Proxy.Trans import Control.Proxy.Trans.Identity import Control.Proxy.Prelude+import Control.PFunctor  {- $modules     "Control.Proxy.Class" defines the 'Proxy' type class that lets you program@@ -42,4 +44,6 @@     "Control.Monad.Trans.Class" exports 'lift'.      "Control.MFunctor" exports 'hoist'.++    "Control.PFunctor" exports 'hoistP'. -}
Control/Proxy/Core/Fast.hs view
@@ -21,6 +21,10 @@     laws, but also guarantees that it works with the other proxy implementations     and with any proxy transformers. -} +{-# LANGUAGE Trustworthy #-}+{- The rewrite RULES require the 'TrustWorthy' annotation.  I've supplied the+   correctness proof for each rewrite rule immediately below each rule. -}+ module Control.Proxy.Core.Fast (     -- * Types     ProxyFast(..),@@ -36,7 +40,6 @@     ) where  import Control.Applicative (Applicative(pure, (<*>)))--- import Control.Monad (ap, forever, liftM, (>=>)) import Control.Monad.IO.Class (MonadIO(liftIO)) import Control.Monad.Trans.Class (MonadTrans(lift)) import Control.MFunctor (MFunctor(hoist))@@ -98,6 +101,37 @@         M          m   -> M (m >>= \p' -> return (go p'))         Pure       r   -> f r +{-# RULES+    "_bind (Request a' Pure) f" forall a' f .+        _bind (Request a' Pure) f = Request a' f;+    "_bind (Respond b  Pure) f" forall b  f .+        _bind (Respond b  Pure) f = Respond b  f+  #-}+{- Proof that the rewrite rules are Trustworthy:++  _bind (Request a' Pure) f+= go (Request a' Pure) where+    go p = case p of+        Request a' fa  -> Request a' (\a  -> go (fa  a))+        Respond b  fb' -> Respond b  (\b' -> go (fb' b'))+        M          m   -> M (m >>= \p' -> return (go p'))+        Pure       r   -> f r+= Request a' (\a -> go (Pure a))+= Request a' (\a -> f a)+= Request a' f++  _bind (Respond b Pure) f+= go (Respond b Pure) where+    go p = case p of+        Request a' fa  -> Request a' (\a  -> go (fa  a))+        Respond b  fb' -> Respond b  (\b' -> go (fb' b'))+        M          m   -> M (m >>= \p' -> return (go p'))+        Pure       r   -> f r+= Respond b (\b' -> go (Pure b'))+= Respond b (\b' -> f b')+= Respond b f+-}+ -- | Only satisfies laws modulo 'observe' instance MonadTrans (ProxyFast a' a b' b) where     lift = _lift@@ -112,7 +146,22 @@     "_lift m ?>= f" forall m f .         _bind (_lift m) f = M (m >>= \r -> return (f r))   #-}+{- Proof that the rewrite rule is Trustworthy: +  _bind (_lift m) f+= _bind (M (m >>= \r -> return (Pure r))) f+= go (M (m >>= \r -> return (Pure r))) where+    go p = case p of+        Request a' fa  -> Request a' (\a  -> go (fa  a))+        Respond b  fb' -> Respond b  (\b' -> go (fb' b'))+        M          m   -> M (m >>= \p' -> return (go p'))+        Pure       r   -> f r+= M ((m >>= \r -> return (Pure r)) >>= \p' -> return (go p'))+= M (m >>= \r -> (return (Pure r) >>= \p' -> return (go p')))+= M (m >>= \r -> return (go (Pure r)))+= M (m >>= \r -> return (f r))+-}+ instance (MonadIO m) => MonadIO (ProxyFast a' a b' b m) where     liftIO m = M (liftIO (m >>= \r -> return (Pure r)))  -- liftIO = M . liftIO . liftM Pure@@ -154,13 +203,6 @@     lift_P = _lift      hoist_P = hoist--{-# RULES-    "_bind (Request a' Pure) f" forall a' f .-        _bind (Request a' Pure) f = Request a' f;-    "_bind (Respond b  Pure) f" forall b  f .-        _bind (Respond b  Pure) f = Respond b  f-  #-}  instance Interact ProxyFast where     k2 \>\ k1 = \a' -> go (k1 a') where
Control/Proxy/Pipe.hs view
@@ -1,11 +1,12 @@-{-# LANGUAGE KindSignatures #-}- {-| This module provides an API similar to "Control.Pipe" for those who prefer     the classic 'Pipe' API.      This module differs slightly from "Control.Pipe" in order to promote     seamless interoperability with both pipes and proxies.  See the \"Upgrade     Pipes to Proxies\" section below for details. -}++{-# LANGUAGE KindSignatures #-}+ module Control.Proxy.Pipe (     -- * Create Pipes     await,@@ -41,7 +42,7 @@ {-| Deliver output downstream      'yield' restores control back downstream and binds its value to 'await'. -}-yield :: (Monad m, Proxy p) => b -> p a' a b' b m ()+yield :: (Monad m, Proxy p) => b -> p a' a () b m () yield b = runIdentityP $ do     respond b     return ()
Control/Proxy/Prelude/Base.hs view
@@ -79,16 +79,17 @@     -- * Modules     -- $modules     module Control.Monad.Trans.State.Strict,-    module Control.Monad.Trans.Writer.Strict,+    module W,     module Data.Monoid     ) where  import Control.MFunctor (hoist) import Control.Monad.Trans.Class (lift)-import Control.Monad.Trans.Writer.Strict (-    WriterT(runWriterT), execWriterT, runWriter, tell )+import Control.Monad.Trans.Writer.Lazy as W (+    WriterT(runWriterT), execWriterT, runWriter )+import Control.Monad.Trans.Writer.Lazy (tell) import Control.Monad.Trans.State.Strict (-    StateT(runStateT), execStateT, runState, execState, get, put )+    StateT(StateT, runStateT), execStateT, runState, execState ) import Control.Proxy.Class import Control.Proxy.Synonym import Control.Proxy.Trans.Identity (runIdentityP, runIdentityK)@@ -723,9 +724,7 @@ foldlD' f = runIdentityK go where     go x = do         a  <- request x-        lift $ do-            b <- get-            put $! f b a+        lift $ StateT $ \b -> let b' = f b a in b' `seq` return ((), b')         x2 <- respond a         go x2 @@ -734,9 +733,7 @@  :: (Monad m, Proxy p) => (b -> a' -> b) -> a' -> p a' x a' x (StateT b m) r foldlU' f = runIdentityK go where     go a' = do-        lift $ do-            b <- get-            put $! f b a'+        lift $ StateT $ \b -> let b' = f b a' in b' `seq` return ((), b')         x   <- request a'         a'2 <- respond x         go a'2
Control/Proxy/Prelude/Kleisli.hs view
@@ -1,14 +1,12 @@-{-# LANGUAGE Rank2Types #-}- -- | Utility functions for Kleisli arrows +{-# LANGUAGE Rank2Types #-}+ module Control.Proxy.Prelude.Kleisli (     -- * Core utility functions     foreverK,     replicateK,     liftK,-    hoistK,-    raiseK,     ) where  import Control.MFunctor (MFunctor(hoist))@@ -51,37 +49,3 @@ liftK :: (Monad m, MonadTrans t) => (a -> m b) -> (a -> t m b) liftK k a = lift (k a) -- liftK = (lift .)--{-| Convenience function equivalent to @(hoist f .)@--> hoistK f p1 >-> hoistK f p2 = hoistK f (p1 >-> p2)->-> hoistK f idT = idT--> hoistK f p1 >=> hoistK f p2 = hoistK f (p1 >=> p2)->-> hoistK f return = return--> hoistK f . hoistK g = hoistK (f . g)->-> hoistK id = id--}-hoistK- :: (Monad m, MFunctor t)- => (forall a . m a -> n a) -> ((b' -> t m b) -> (b' -> t n b))-hoistK k p a' = hoist k (p a')--- hoistK k = (hoist k .)--{-| Convenience function equivalent to @(hoist lift .)@--> raiseK p1 >-> raiseK p2 = raiseK (p1 >-> p2)->-> raiseK idT = idT--> raiseK p1 >=> raiseK p2 = raiseK (p1 >=> p2)->-> raiseK return = return--}-raiseK- :: (Monad m, MFunctor t1, MonadTrans t2) => (q -> t1 m r) -> (q -> t1 (t2 m) r)-raiseK = (hoist lift .)
Control/Proxy/Synonym.hs view
@@ -1,7 +1,7 @@-{-# LANGUAGE KindSignatures #-}- {-| These type synonyms simplify type signatures when proxies do not use all     their type variables. -}++{-# LANGUAGE KindSignatures #-}  module Control.Proxy.Synonym (     -- * Synonyms
Control/Proxy/Trans/Either.hs view
@@ -1,6 +1,6 @@ -- | This module provides the proxy transformer equivalent of 'EitherT'. -{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE KindSignatures, CPP #-}  module Control.Proxy.Trans.Either (     -- * EitherP@@ -24,7 +24,10 @@ import Control.PFunctor (PFunctor(hoistP)) import Control.Proxy.Class import Control.Proxy.Trans (ProxyTrans(liftP))+#if MIN_VERSION_base(4,6,0)+#else import Prelude hiding (catch)+#endif  -- | The 'Either' proxy transformer newtype EitherP e p a' a b' b (m :: * -> *) r
Control/Proxy/Trans/Reader.hs view
@@ -7,11 +7,11 @@     ReaderP(..),     runReaderP,     runReaderK,-    withReaderP,     -- * Reader operations     ask,-    local,     asks,+    local,+    withReaderP,     ) where  import Control.Applicative (Applicative(pure, (<*>)), Alternative(empty, (<|>)))@@ -133,12 +133,6 @@ runReaderK i p q = runReaderP i (p q) -- runReaderK i = (runReaderP i .) --- | Modify a computation's environment (a more general version of 'local')-withReaderP- :: (j -> i) -> ReaderP i p a' a b' b m r -> ReaderP j p a' a b' b m r-withReaderP f p = ReaderP (\i -> unReaderP p (f i))--- withReaderP f p = ReaderP $ unReaderP p . f- -- | Get the environment ask :: (Proxy p, Monad m) => ReaderP i p a' a b' b m i ask = ReaderP return_P@@ -151,3 +145,9 @@ local  :: (i -> i) -> ReaderP i p a' a b' b m r -> ReaderP i p a' a b' b m r local = withReaderP++-- | Modify a computation's environment (a more general version of 'local')+withReaderP+ :: (j -> i) -> ReaderP i p a' a b' b m r -> ReaderP j p a' a b' b m r+withReaderP f p = ReaderP (\i -> unReaderP p (f i))+-- withReaderP f p = ReaderP $ unReaderP p . f
Control/Proxy/Tutorial.hs view
@@ -66,7 +66,6 @@ import Control.Proxy import Control.Proxy.Core.Correct (ProxyCorrect) import Control.Proxy.Trans.Either-import Prelude hiding (catch)  {- $intro     The @pipes@ library replaces lazy 'IO' with a safe, elegant, and@@ -91,10 +90,10 @@ > import Control.Proxy > import System.IO > -> --                Produces Strings ---+----------+-> --                                    |          |-> --                                    v          v-> lines' :: (Proxy p) => Handle -> () -> Producer p String IO r+> --                 Produces Strings ---+----------++> --                                     |          |+> --                                     v          v+> lines' :: (Proxy p) => Handle -> () -> Producer p String IO () > lines' h () = runIdentityP loop where >     loop = do >         eof <- lift $ hIsEOF h@@ -138,9 +137,9 @@ > --                Self-contained session ---+         +--+-- These must match > --                                          |         |  |   each component > --                                          v         v  v-> promptInt >-> printer :: (Proxy p) => () -> Session p IO r-> > lines' h  >-> printer :: (Proxy p) => () -> Session p IO ()+>+> promptInt >-> printer :: (Proxy p) => () -> Session p IO r      ('>->') connects each 'request' in @printer@ with a 'respond' in     @lines'@ or @promptInt@.@@ -157,7 +156,7 @@     The following program never brings more than a single line into memory (not     that it matters for such a small file): ->>> withFile "test.txt" $ \h -> runProxy $ lines' h >-> printer+>>> withFile "test.txt" ReadMode $ \h -> runProxy $ lines' h >-> printer Received a value: "Line 1" Received a value:@@ -220,7 +219,8 @@      * You can define your own lazy components that have nothing to do with files -    * @pipes@ never uses 'unsafePerformIO' or violates referential transparency.+    * @pipes@ never uses 'unsafePerformIO' and never violates referential+      transparency.      * You don't need strictness hacks to ensure the proper ordering of effects @@ -811,14 +811,14 @@     When you compose two proxies, you interleave their effects in the base     monad.  The following two proxies demonstrate this interleaving of effects: -> downstream :: (Proxy p) => Consumer p () IO ()+> downstream :: (Proxy p) => () -> Consumer p () IO () > downstream () = runIdentityP $ do >     lift $ print 1 >     request ()  -- Switch to upstream >     lift $ print 3 >     request ()  -- Switch to upstream >-> upstream :: (Proxy p) => Producer p () IO ()+> upstream :: (Proxy p) => () -> Producer p () IO () > upstream () = runIdentityP $ do >     lift $ print 2 >     respond () -- Switch to downstraem@@ -999,7 +999,7 @@      The @S@ suffix indicates that it belongs in the \'@S@\'erver position. -    @(takeB_ n)@ allows at most @n@ value to pass through it in \'@B@\'oth+    @(takeB_ n)@ allows at most @n@ values to pass through it in \'@B@\'oth     directions:  > takeB_ :: (Monad m, Proxy p) => Int -> a' -> p a' a a' a m ()@@ -1071,7 +1071,7 @@ Received a value: 37 -    What about our original @lines@ function?  That's just 'hGetLineS':+    What about our original @lines'@ function?  That's just 'hGetLineS':  > hGetLineS :: (Proxy p) => Handle -> () -> Producer p String IO () @@ -1094,7 +1094,7 @@     Composition isn't the only way to assemble proxies.  You can also sequence     predefined proxies using @do@ notation to generate more elaborate behaviors. -    Most commonly, you will sequence two sources to combine their outputs, very+    Most commonly, you will sequence sources to combine their outputs, very     similar to how the Unix @cat@ utility behaves:  > threeSources () = do@@ -1262,7 +1262,7 @@     You can also run multiple folds at the same time just by adding more     'WriterT' layers to your base monad: ->>> runWriterT $ runWriterT $ fromListS [9, 10] >-> anyD even >-> raiseK sumD+>>> runWriterT $ runWriterT $ runProxy $ fromListS [9, 10] >-> anyD even >-> raiseK sumD (((), Any {getAny = True},Sum {getSum = 19})      I designed certain special folds to terminate the 'Session' early if they@@ -1297,8 +1297,8 @@     and write a streaming utility that lazily opens a file only in response to     a 'request', such as the following 'Producer': -> readFile' :: FilePath -> () -> Producer p String IO-> readFile' file () = runIdentityP $ do+> readFileS :: FilePath -> () -> Producer p String IO+> readFileS file () = runIdentityP $ do >     h <- lift $ openFile file ReadMode >     lift $ putStrLn "Opening file" >     hGetLineS h ()@@ -1307,7 +1307,7 @@      This works well if we fully demand the file: ->>> runProxy $ readFile' "test.txt" >-> printD+>>> runProxy $ readFileS "test.txt" >-> printD Opening file "Line 1" "Line 2"@@ -1317,27 +1317,32 @@     This also works well if we never demand the file at all, in which case we     never open it: ->>> runProxy $ readFile' "test.txt" >-> return+>>> runProxy $ readFileS "test.txt" >-> return -- Outputs nothing      But it gives exactly the wrong behavior if we partially demand the file: ->>> runProxy $ readFile' "test.txt" >-> takeB_ 1 >-> printD+>>> runProxy $ readFileS "test.txt" >-> takeB_ 1 >-> printD Opening file "Line 1"      Notice that this does not close the file, because once @takeB_ 1@ terminates-    it terminates the entire 'Session' and @readFile'@ does not get a chance to+    it terminates the entire 'Session' and @readFileS@ does not get a chance to     finalize the file. -    I will release a separate library in the near future that offers lazy-    resource management, too, but in the meantime I advise that you use one of-    the following two strategies to guarantee deterministic resource-    deallocation.+    The @pipes-safe@ library solves this problem by providing resource+    management abstractions built on top of @pipes@ and offers several other+    nice features: -    The first approach opens all resources before running the session and close+    * It is completely exception safe, even against asynchronous exceptions++    * It is backwards compatible with \"unmanaged\" ordinary proxies++    Backwards compatibility means that you don't need to buy in to the+    @pipes-safe@ way of doing things.  For example, another common approach is+    to just open all resources before running the session and close     them all afterward.  For example, if I wanted to emulate the Unix @cp@-    command, streaming one line at a time, I would write:+    command, streaming one line at a time, I might write:  > import System.IO >@@ -1345,46 +1350,36 @@ > cp inFile outFile = >     withFile file1 ReadMode  $ \hIn  -> >     withFile file2 WriteMode $ \hOut ->->     runProxy $ hGetLineS hIn >-> hPutLineS hOut2--    The advantage of this approach is that it:+>     runProxy $ hGetLineS hIn >-> hPutLineS hOut -    * is straightforward,+    Some people prefer that approach because it: -    * requires no special integration with existing libraries, and+    * is straightforward, and -    * is exception safe.+    * can reuse functions from @Control.Exception@      The disadvantage is that this does not lazily allocate resources, nor does-    this promptly deallocate them.--    The second approach is to use something like 'ResourceT' (from the-    @resourceT@ package) to register finalizers and ensure they get released-    deterministically.  You may prefer this approach if you have previously used-    the @conduit@ library, which uses 'ResourceT' in its base monad to offer-    resource determinism.  You can use 'ResourceT' with @pipes@, too, just by-    including it in the base monad.--    I plan to release a lazy resource management library very soon built on top-    of @pipes@ that behaves similarly to 'ResourceT'.  The main advantages of-    this upcoming implementation will be that it:+    this promptly deallocate them.  Also, there is no way to recover from+    exceptions and resume the 'Session'.  On the other hand, @pipes-safe@ lets+    you do all of these. -    * uses a simpler and pure implementation+    Fortunately, you can choose whichever approach you prefer and rest assured+    that the two approaches safely interoperate.  @Control.Proxy.Safe.Tutorial@+    from the @pipes-safe@ package provides a separate tutorial on how to: -    * obeys several useful theoretical laws+    * extend @pipes@ with resource management, -    * requires no dependencies other than @pipes@+    * handle exceptions natively within proxies, and -    However, if you don't need this extra power, then just stick to the former-    simpler approach.  I plan to release all standard libraries to be agnostic-    of the finalization approach to let you use which one you prefer.+    * interoperate with unmanaged code. -}  {- $extend     This library provides several extensions that add features on top of the     base 'Proxy' API.  These extensions behave like monad transformers, except     that they also lift the 'Proxy' class through the extension so that the-    extended proxy can still 'request', 'respond', compose with other proxies:+    extended proxy can still 'request', 'respond', and compose with other+    proxies:  > instance (Proxy p) => Proxy (IdentityP p)  -- Equivalent to IdentityT > instance (Proxy p) => Proxy (EitherP e p)  -- Equivalent to EitherT@@ -1411,8 +1406,8 @@ >         Just n  -> respond n      There is no way to recover from the error and resume streaming data.  You-    can only handle 'Left' value after using 'runProxy', but by then it is too -    late.+    can only handle the 'Left' value after using 'runProxy', but by then it is+    too late.      We can solve this by switching the order of the two monad transformers, but     using 'EitherP' this time instead of 'EitherT':@@ -1474,7 +1469,7 @@ >     lift $ putStrLn err  -- Print the error >     heartbeat p          -- Restart 'p' -    This uses the 'catch' function from "Control.Proxy.Trans.Either", which+    This uses the 'E.catch' function from "Control.Proxy.Trans.Either", which     lets you catch and handle errors locally without disturbing other proxies.  >>> runProxy $ E.runEitherK $ (heartbeat . promptInt3) >-> takeB_ 2 >-> printer@@ -1560,13 +1555,14 @@  > zipD >  :: (Monad m, Proxy p1, Proxy p2, Proxy p3)->  => () -> Consumer p1 a (Consumer p2 b (Consumer p3 (a, b) m)) r-> zipD = runIdentityP . hoist (runIdentityP . hoist runIdentityP) $ forever $ do+>  => () -> Consumer p1 a (Consumer p2 b (Producer p3 (a, b) m)) r+> zipD () =+>     runIdentityP . hoist (runIdentityP . hoist runIdentityP) $ forever $ do >     -- Yes, this 'runIdentityP' mess is necessary.  Sorry! >->     a <- request ()               -- Request from the outer 'Consumer'->     b <- lift $ request ()        -- Request from the inner 'Consumer'->     lift $ lift $ respond (a, b)  -- Respond to the 'Producer'+>         a <- request ()               -- Request from the outer 'Consumer'+>         b <- lift $ request ()        -- Request from the inner 'Consumer'+>         lift $ lift $ respond (a, b)  -- Respond to the 'Producer'      'zipD' behaves analogously to a curried function.  We partially apply it to     each layer using composition and 'runProxyK' or 'runProxy':@@ -1699,15 +1695,15 @@ >       :: (Monad m, Proxy p) >       => p a' a b' b m r -> t p a' a b' b m r >->  -- mapP is slightly more elegant->     mapP->      :: (Monad m, Proxy p)->      => (q -> p a' a b' b m r) -> (q -> t p a' a b' b m r)->     mapP = (liftP . )+> -- mapP is slightly more elegant+> mapP+>  :: (Monad m, Proxy p, ProxyTrans t)+>  => (q -> p a' a b' b m r) -> (q -> t p a' a b' b m r)+> mapP = (liftP . ) -    It's very easy to use.  Just use 'mapP' (equivalent to @(liftP .)@ to lift-    one proxy transformer to match another one.  For example, we can 'mapP'-    @increment2@ to match @promptInt3@:+    It's very easy to use.  Just use 'mapP' to lift one proxy transformer to+    match another one.  For example, we can 'mapP' @increment2@ to match+    @promptInt3@:  > promptInt3 >-> mapP increment2 >  :: (Proxy p) => () -> Session (EitherP String (StateP Int p)) IO r@@ -1773,10 +1769,9 @@ > > (liftP .) return = return -    The only difference is that I also include 'mapP' in the 'ProxyTrans' type-    class for convenience, which sweetens these laws a little bit:+    The only difference is 'mapP' sweetens these laws a little bit: -> mapP = (lift .)+> mapP = (liftP .) > > mapP (f >=> g) = mapP f >=> mapP g  -- These are functor laws! >@@ -1788,7 +1783,7 @@      This means that we need a set of laws that guarantee that the proxy     transformer lifts the 'Proxy' instance correctly.  I call these laws the-    \"proxy transformer laws\":+    \"proxy morphism laws\":  > mapP (f >-> g) = mapP f >-> mapP g  -- These are functor laws, too! >@@ -1828,16 +1823,16 @@ > > mapP respond = respond -    We can translate those to 'liftP' to get:+    We can translate those back to 'liftP' to get: -> liftP $ request a' = request a'+> liftP (request a') = request a' >-> liftP $ respond b  = respond b+> liftP (respond b)  = respond b      In other words, 'request' and 'respond' in the extended proxy must behave     exactly the same as lifting 'request' and 'respond' from the base proxy. -    All the proxy transformers in this library obey the proxy transformer laws,+    All the proxy transformers in this library obey the proxy morphism laws,     which ensure that 'liftP' / 'mapP' always do \"the right thing\".      Proxy transformers also implement 'hoistP' from the 'PFunctor' class in
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2012, Gabriel Gonzalez+Copyright (c) 2012, 2013 Gabriel Gonzalez All rights reserved.  Redistribution and use in source and binary forms, with or without modification,
pipes.cabal view
@@ -1,10 +1,10 @@ Name: pipes-Version: 3.0.0+Version: 3.1.0 Cabal-Version: >=1.14.0 Build-Type: Simple License: BSD3 License-File: LICENSE-Copyright: 2012 Gabriel Gonzalez+Copyright: 2012, 2013 Gabriel Gonzalez Author: Gabriel Gonzalez Maintainer: Gabriel439@gmail.com Bug-Reports: https://github.com/Gabriel439/Haskell-Pipes-Library/issues