packages feed

pipes 2.0.0 → 2.1.0

raw patch · 9 files changed

+1816/−1452 lines, 9 filesdep +index-corePVP ok

version bump matches the API change (PVP)

Dependencies added: index-core

API changes (from Hackage documentation)

- Control.Monad.Trans.Free: Pure :: r -> FreeF f r x
- Control.Pipe.Common: (<+<) :: (Monad m) => Pipe b c m r -> Pipe a b m r -> Pipe a c m r
- Control.Pipe.Common: (>+>) :: (Monad m) => Pipe a b m r -> Pipe b c m r -> Pipe a c m r
- Control.Pipe.Common: Await :: (a -> x) -> PipeF a b x
- Control.Pipe.Common: Lazy :: Pipe a b m r -> Lazy m r a b
- Control.Pipe.Common: Yield :: (b, x) -> PipeF a b x
- Control.Pipe.Common: [unLazy] :: Lazy m r a b -> Pipe a b m r
- Control.Pipe.Common: await :: (Monad m) => Pipe a b m a
- Control.Pipe.Common: data PipeF a b x
- Control.Pipe.Common: idP :: (Monad m) => Pipe a a m r
- Control.Pipe.Common: infixl 9 >+>
- Control.Pipe.Common: infixr 9 <+<
- Control.Pipe.Common: instance GHC.Base.Functor (Control.Pipe.Common.PipeF a b)
- Control.Pipe.Common: instance GHC.Base.Monad m => Control.Category.Category (Control.Pipe.Common.Lazy m r)
- Control.Pipe.Common: newtype Lazy m r a b
- Control.Pipe.Common: pipe :: (Monad m) => (a -> b) -> Pipe a b m r
- Control.Pipe.Common: runPipe :: (Monad m) => Pipeline m r -> m r
- Control.Pipe.Common: type Consumer b = Pipe b Void
- Control.Pipe.Common: type Pipe a b = FreeT (PipeF a b)
- Control.Pipe.Common: type Pipeline = Pipe () Void
- Control.Pipe.Common: type Producer b = Pipe () b
- Control.Pipe.Common: yield :: (Monad m) => b -> Pipe a b m ()
- Control.Pipe.Final: (<-<) :: (Monad m) => Frame b c m r -> Frame a b m r -> Frame a c m r
- Control.Pipe.Final: (>->) :: (Monad m) => Frame a b m r -> Frame b c m r -> Frame a c m r
- Control.Pipe.Final: Frame :: Ensure a b m (Ensure () b m r) -> Frame a b m r
- Control.Pipe.Final: FrameC :: Frame a b m r -> FrameC m r a b
- Control.Pipe.Final: [unFrameC] :: FrameC m r a b -> Frame a b m r
- Control.Pipe.Final: [unFrame] :: Frame a b m r -> Ensure a b m (Ensure () b m r)
- Control.Pipe.Final: awaitF :: (Monad m) => Ensure a b m a
- Control.Pipe.Final: bindClosed :: (Monad m) => Frame a b m r1 -> (r1 -> Ensure () b m r2) -> Frame a b m r2
- Control.Pipe.Final: catchP :: (Monad m) => m () -> Ensure a b m r -> Ensure a b m r
- Control.Pipe.Final: close :: (Monad m) => Ensure () b m r -> Ensure a b m (Ensure () b m r)
- Control.Pipe.Final: finallyP :: (Monad m) => m () -> Ensure a b m r -> Ensure a b m r
- Control.Pipe.Final: idF :: (Monad m) => Frame a a m r
- Control.Pipe.Final: instance GHC.Base.Monad m => Control.Category.Category (Control.Pipe.Final.FrameC m r)
- Control.Pipe.Final: instance GHC.Base.Monad m => GHC.Base.Functor (Control.Pipe.Final.Frame a b m)
- Control.Pipe.Final: newtype Frame a b m r
- Control.Pipe.Final: newtype FrameC m r a b
- Control.Pipe.Final: reopen :: (Monad m) => Frame a b m r -> Ensure a b m r
- Control.Pipe.Final: runFrame :: (Monad m) => Stack m r -> m r
- Control.Pipe.Final: type Ensure a b m r = Pipe (Maybe a) (m (), b) m r
- Control.Pipe.Final: type Prompt p a b m r = p a b m (p () b m r)
- Control.Pipe.Final: type Stack = Frame () Void
- Control.Pipe.Final: yieldF :: (Monad m) => b -> Ensure a b m ()
+ Control.Frame: (<-<) :: Monad m => Frame c m (M b) C r -> Frame b m (M a) C r -> Frame c m (M a) C r
+ Control.Frame: (>->) :: Monad m => Frame b m (M a) C r -> Frame c m (M b) C r -> Frame c m (M a) C r
+ Control.Frame: FrameC :: Frame b m (M a) C r -> FrameC m r a b
+ Control.Frame: [Await] :: (a -> x (O a)) -> FrameF b x (O a)
+ Control.Frame: [Close] :: x C -> FrameF b x (O a)
+ Control.Frame: [Yield] :: b -> x i -> FrameF b x i
+ Control.Frame: [unFrameC] :: FrameC m r a b -> Frame b m (M a) C r
+ Control.Frame: await :: (Monad m) => Frame b m (M a) (M a) a
+ Control.Frame: awaitF :: (Monad m) => Frame b m (M a) (M a) (Maybe a)
+ Control.Frame: catchD :: (Monad m) => m () -> Frame b m i j r -> Frame b m i j r
+ Control.Frame: catchF :: (Monad m) => m () -> Frame b m (M a) j r -> Frame b m (M a) j r
+ Control.Frame: close :: (Monad m) => Frame b m (M a) C ()
+ Control.Frame: data C
+ Control.Frame: data FrameF b x i
+ Control.Frame: data O a
+ Control.Frame: finallyD :: (Monad m) => m () -> Frame b m i j r -> Frame b m i j r
+ Control.Frame: finallyF :: (Monad m) => m () -> Frame b m (M a) j r -> Frame b m (M a) j r
+ Control.Frame: idF :: (Monad m) => Frame a m (M a) C r
+ Control.Frame: infixr 9 >->
+ Control.Frame: instance Control.IMonad.Core.IFunctor (Control.Frame.FrameF b)
+ Control.Frame: instance GHC.Base.Monad m => Control.Category.Category (Control.Frame.FrameC m r)
+ Control.Frame: newtype FrameC m r a b
+ Control.Frame: runFrame :: (Monad m) => Stack m r -> m r
+ Control.Frame: type Frame b m i j r = IFreeT (FrameF (m (), b)) (U m) (r := j) i
+ Control.Frame: type M a = O (Maybe a)
+ Control.Frame: type Stack m r = Frame Void m (M ()) C r
+ Control.Frame: yield :: (Monad m) => b -> Frame b m i i ()
+ Control.Frame: yieldF :: (Monad m) => m () -> b -> Frame b m i i ()
+ Control.IMonad.Trans.Free: IFreeT :: m (IFreeF f r (IFreeT f m r)) i -> IFreeT f m r i
+ Control.IMonad.Trans.Free: Return :: (r i) -> IFreeF f r i
+ Control.IMonad.Trans.Free: Wrap :: (f x i) -> IFreeF f r i
+ Control.IMonad.Trans.Free: [runIFreeT] :: IFreeT f m r i -> m (IFreeF f r (IFreeT f m r)) i
+ Control.IMonad.Trans.Free: data IFreeF f r (x :: * -> *) i
+ Control.IMonad.Trans.Free: data IFreeT f m r i
+ Control.IMonad.Trans.Free: instance (Control.IMonad.Core.IFunctor f, Control.IMonad.Core.IMonad m) => Control.IMonad.Core.IFunctor (Control.IMonad.Trans.Free.IFreeT f m)
+ Control.IMonad.Trans.Free: instance (Control.IMonad.Core.IFunctor f, Control.IMonad.Core.IMonad m) => Control.IMonad.Core.IMonad (Control.IMonad.Trans.Free.IFreeT f m)
+ Control.IMonad.Trans.Free: instance Control.IMonad.Core.IFunctor f => Control.IMonad.Trans.IMonadTrans (Control.IMonad.Trans.Free.IFreeT f)
+ Control.IMonad.Trans.Free: liftF :: (IFunctor f, IMonad m) => f r :-> IFreeT f m r
+ Control.IMonad.Trans.Free: wrap :: (IMonad m) => f (IFreeT f m r) :-> IFreeT f m r
+ Control.Monad.Trans.Free: Return :: r -> FreeF f r x
+ Control.Monad.Trans.Free: liftF :: (Functor f, Monad m) => f r -> FreeT f m r
+ Control.Pipe: (<+<) :: (Monad m) => Pipe b c m r -> Pipe a b m r -> Pipe a c m r
+ Control.Pipe: (>+>) :: (Monad m) => Pipe a b m r -> Pipe b c m r -> Pipe a c m r
+ Control.Pipe: Await :: (a -> x) -> PipeF a b x
+ Control.Pipe: PipeC :: Pipe a b m r -> PipeC m r a b
+ Control.Pipe: Yield :: (b, x) -> PipeF a b x
+ Control.Pipe: [unPipeC] :: PipeC m r a b -> Pipe a b m r
+ Control.Pipe: await :: (Monad m) => Pipe a b m a
+ Control.Pipe: data PipeF a b x
+ Control.Pipe: idP :: (Monad m) => Pipe a a m r
+ Control.Pipe: infixl 9 >+>
+ Control.Pipe: infixr 9 <+<
+ Control.Pipe: instance GHC.Base.Functor (Control.Pipe.PipeF a b)
+ Control.Pipe: instance GHC.Base.Monad m => Control.Category.Category (Control.Pipe.PipeC m r)
+ Control.Pipe: newtype PipeC m r a b
+ Control.Pipe: pipe :: (Monad m) => (a -> b) -> Pipe a b m r
+ Control.Pipe: runPipe :: (Monad m) => Pipeline m r -> m r
+ Control.Pipe: type Consumer b = Pipe b Void
+ Control.Pipe: type Pipe a b = FreeT (PipeF a b)
+ Control.Pipe: type Pipeline = Pipe () Void
+ Control.Pipe: type Producer b = Pipe () b
+ Control.Pipe: yield :: (Monad m) => b -> Pipe a b m ()

Files

+ Control/Frame.hs view
@@ -0,0 +1,477 @@+{-|+    'Frame's extend 'Pipe's with:++    * The ability to fold input++    * Prompt and deterministic finalization++    'Frame's differ from 'Pipe's because they form restricted monads rather than+    forming ordinary monads.  This means you must rebind @do@ notation to use+    restricted monads from the @index-core@ package.  See the \"Create Frames\"+    section for details.  For even more details, consult the @index-core@+    package.+-}++{-# LANGUAGE GADTs, TypeOperators #-}++module Control.Frame (+    -- * Types+    -- $types+    C,+    O,+    M,+    FrameF(..),+    Frame,+    Stack,+    -- * Create Frames+    -- $create++    -- ** Primitives+    -- $primitives+    yieldF,+    awaitF,+    close,+    -- ** Pipe-like primitives+    -- $pipeprims+    yield,+    await,+    -- * Finalize Frames+    -- $finalization+    catchD,+    catchF,+    finallyD,+    finallyF,+    -- * Compose Frames+    -- $compose+    (<-<),+    (>->),+    idF,+    FrameC(..),+    -- * Run Frames+    -- $run+    runFrame+    ) where++import Control.Category+import Control.IMonad+import Control.IMonad.Trans+import Control.IMonad.Trans.Free+import Control.Monad.Instances ()+import Data.Maybe+import Data.Void+import Prelude hiding ((.), id)++-- For documentation+import Control.Pipe hiding (await, yield, Await, Yield)++{- $types+    The first step to convert 'Pipe' code to 'Frame' code is to translate the+    types.  All types of the form \"@Pipe a b m r@\" become+    \"@Frame b m (M a) C r@\".  For example, given the following type signatures+    from the tutorial:++> printer  :: (Show a) => Pipe b Void IO r+> take'    :: Int -> Pipe b b IO ()+> fromList :: (Monad m) => [b] -> Pipe () b m ()++    ... you would replace them with:++> printer  :: (Show a) => Frame Void IO (M a) C r+> take'    :: Int -> Frame a IO (M a) C ()+> fromList :: (Monad m) => [a] -> Frame a m (M ()) C ()+> -- To use the finalization example, change fromList's base monad to 'IO'+> fromList :: [a] -> Frame a IO (M ()) C ()+-}++-- | Index representing an open input end, receiving values of type @a@+data O a++-- | Index representing a closed input end+data C++-- | Index representing an open input end, receiving values of type @Maybe a@+type M a = O (Maybe a)++{-|+    Base functor for a pipe that can close its input end++    * @b@ - Output type++    * @x@ - Next step++    * @i@ - Current step's index+-}+data FrameF b x i where+    Yield ::  b -> x    i   -> FrameF b x    i+    Await :: (a -> x (O a)) -> FrameF b x (O a)+    Close ::       x    C   -> FrameF b x (O a)++instance IFunctor (FrameF b) where+    fmapI f p = case p of+        Yield b y -> Yield b (f y)+        Await a   -> Await (f . a)+        Close c   -> Close (f c)++{-|+    A 'Frame' is like a 'Pipe' with an indexed input end:++    * @b@ - The type of the 'Frame's output++    * @m@ - The base monad++    * @i@ - The initial index of the input end ('O'pen or 'C'losed)++    * @j@ - The final index of the input end ('O'pen or 'C'losed)++    * @r@ - The return value+-}+type Frame b m i j r = IFreeT (FrameF (m (), b)) (U m) (r := j) i++-- | A self-contained 'Frame' that is ready to be run+type Stack m r = Frame Void m (M ()) C r++-- $create+-- The second step to convert 'Pipe' code to 'Frame' code is to change your+-- module header to:+--+-- > {-# LANGUAGE RebindableSyntax #-}+-- >+-- > import Control.IMonad.Do+-- > import Control.Frame+-- > import Prelude hiding (Monad(..))+--+-- "Control.Frame" replaces all 'Pipe' 'await's and 'yield's with their+-- corresponding 'Frame' counterparts.  @Control.IMonad.Do@ rebinds @do@+-- notation to work with restricted monads, which also requires using the+-- @RebindableSyntax@ extension and hiding the 'Monad' class from the @Prelude@.+--+-- You also must use the restricted monad utility functions, which have the+-- same name as their ordinary monad counterparts except with an \'@R@\' suffix,+-- such as 'foreverR' instead of 'forever'.  Finally, you must use 'liftU'+-- instead of 'lift' to invoke operations in the base monad.+--+-- Finally, every terminating 'Frame' must be 'close'd exactly once before being+-- passed to composition.+--+-- > printer = foreverR $ do+-- >     a <- await+-- >     liftU $ print a+-- >+-- > take' n = do+-- >     replicateMR_ n $ do+-- >         a <- await+-- >         yield a+-- >     close+-- >     liftU $ putStrLn "You shall not pass!"+-- >+-- > fromList xs = do+-- >     close+-- >     mapMR_ yield xs++{- $primitives+    'yieldF' guards against downstream termination by yielding the most+    up-to-date finalization alongside each value, so that downstream can call+    that finalizer if it terminates before requesting another value.++    'awaitF' intercepts upstream termination by returning a 'Nothing' if+    upstream terminates before providing a value.  Further attempts to request+    input from upstream will terminate the current 'Frame' using the+    return value provided from upstream.++    While 'awaitF' is useful for folds, 'yieldF' is less useful for end-users of+    this library and the higher-order 'catchF' / 'finallyF' finalization+    functions are much more user-friendly.++    Composing two 'Frame's requires that each 'Frame' invokes 'close' exactly+    once.  Anything else will not type-check.  Leave out the 'close' statement+    when writing library components and let the person assembling the components+    for composition specify where the 'close' goes.++    The earlier you 'close' the upstream 'Frame', the earlier it is finalized.+    However, once you 'close' it you may no longer 'await'.+-}++-- | 'Yield' the most current finalizer for this 'Frame' alongside the value+yieldF :: (Monad m) => m () -> b -> Frame b m i i ()+yieldF m x = liftF $ Yield (m, x) (V ())++-- | 'Await' a value from upstream, returning 'Nothing' if upstream terminates+awaitF :: (Monad m) => Frame b m (M a) (M a) (Maybe a)+awaitF = liftF $ Await V++-- | 'Close' the input end, calling the finalizers of every upstream 'Frame'+close :: (Monad m) => Frame b m (M a) C ()+close = liftF $ Close (V ())++{- $pipeprims+    The following 'Pipe'-like primitives are built on top of the 'Frame'+    primitives.  They behave identically to their 'Pipe' counterparts and can+    be used as drop-in replacements for them.+-}++-- | 'yield' a value upstream alongside an empty finalizer+yield :: (Monad m) => b -> Frame b m i i ()+yield = yieldF (return ())++-- | 'await' a value from upstream and terminate if upstream terminates+await :: (Monad m) => Frame b m (M a) (M a) a+await = awaitF !>= maybe await returnR++{- $finalization+    The third (and optional) step to convert 'Pipe' code to 'Frame' code is to+    register finalizers for your 'Frame'.  These finalizers may be arbitrarily+    nested:++> printer = foreverR $ catchF (putStrLn "printer interrupted") $ do+>     a <- await+>     liftU $ print a+>+> take' n = finallyF (putStrLn "You shall not pass!") $ do+>     replicateMR_ n $ do+>         a <- catchF (putStrLn "take' interrupted") await+>         yield a+>     close+>+> fromList xs = catchF (putStrLn "fromList interrupted") $ do+>     close+>     mapMR_ yield xs++    These convenience functions register block-level finalizers to be called if+    another 'Frame' terminates first.  The naming conventions are:++    * \"catch\" functions (i.e. 'catchD' / 'catchF') call the finalizer only if+      another 'Frame' terminates before the block completes, but will not call+      the finalizer if the block terminates normally.++    * \"finally\" functions (i.e. 'finallyD' / 'finallyF') are like \"catch\"+      functions except that they also call the finalizer if the block terminates+      normally.++    * Functions that end in a \'@D@\' suffix (i.e. 'catchD' / 'finallyD') only+      guard against downstream termination.++    * Functions that end in a \'@F@\' suffix (i.e. 'catchF' / 'finallyF') guard+      against termination in both directions.  You usually want these ones.++    Note that finalization blocks that /begin/ after the 'close' statement may+    only use the \'@D@\'-suffixed version as upstream has been closed off.  This+    is a consequence of a deficiency in Haskell's type system that will take+    time to work around.  However an \'@F@\'-suffixed block that begins before a+    'close' statement may continue through it normally.  So, for code blocks+    after a 'close' statement, use 'catchD' \/ 'finallyD', otherwise use+    'catchF' \/ 'finallyF'.  In future releases, the \'@D@\'-suffixed versions+    will be removed and merged into the \'@F@\'-suffixed versions.+-}++{-|+    @catchD m p@ calls the finalizer @m@ if a downstream 'Frame' terminates+    before @p@ finishes.+-}+catchD :: (Monad m) => m () -> Frame b m i j r -> Frame b m i j r+catchD m p = IFreeT $ U $ do+    x <- unU $ runIFreeT p+    unU $ runIFreeT $ case x of+        Return r                -> returnI r+        Wrap (Close         p') -> wrap $ Close (catchD m p')+        Wrap (Yield (m', b) p') -> wrap $ Yield (m' >> m, b) (catchD m p')+        Wrap (Await         f ) -> wrap $ Await $ fmap (catchD m) f++{-|+    @catchF m p@ calls the finalizer @m@ if any 'Frame' terminates before @p@+    finishes.+-}+catchF :: (Monad m) => m () -> Frame b m (M a) j r -> Frame b m (M a) j r+catchF m p = IFreeT $ U $ do+    x <- unU $ runIFreeT p+    unU $ runIFreeT $ case x of+        Return r                -> returnI r+        Wrap (Close         p') -> wrap $ Close $ catchD m p'+        Wrap (Yield (m', b) p') -> wrap $ Yield (m' >> m, b) (catchF m p')+        Wrap (Await         f ) -> wrap $ Await $ \e -> case e of+            Nothing -> liftU m !> catchF m (f e)+            Just _  ->            catchF m (f e)++{-|+    @finallyD m p@ calls the finalizer @m@ if a downstream 'Frame' terminates+    before @p@ finishes or if @p@ completes normally.+-}+finallyD :: (Monad m) => m () -> Frame b m i j r -> Frame b m i j r+finallyD m p = IFreeT $ U $ do+    x <- unU $ runIFreeT p+    unU $ runIFreeT $ case x of+        Return r                -> liftU m !> returnI r+        Wrap (Close         p') -> wrap $ Close (finallyD m p')+        Wrap (Yield (m', b) p') -> wrap $ Yield (m' >> m, b) (finallyD m p')+        Wrap (Await         f ) -> wrap $ Await $ fmap (finallyD m) f++{-|+    @finallyF m p@ calls the finalizer @m@ if any 'Frame' terminates before @p@+    finishes or if @p@ completes normally.+-}+finallyF :: (Monad m) => m () -> Frame b m (M a) j r -> Frame b m (M a) j r+finallyF m p = IFreeT $ U $ do+    x <- unU $ runIFreeT p+    unU $ runIFreeT $ case x of+        Return r                -> liftU m !> returnI r+        Wrap (Close         p') -> wrap $ Close $ finallyD m p'+        Wrap (Yield (m', b) p') -> wrap $ Yield (m' >> m, b) (finallyF m p')+        Wrap (Await         f ) -> wrap $ Await $ \e -> case e of+            Nothing -> liftU m !> finallyF m (f e)+            Just _  ->            finallyF m (f e)++(<~<) :: (Monad m)+ => IFreeT (FrameF c) (U m) (r := C) (O b)+ -> IFreeT (FrameF b) (U m) (r := C) (O a)+ -> IFreeT (FrameF c) (U m) (r := C) (O a)+p1 <~< p2 = IFreeT $ U $ do+    x1 <- unU $ runIFreeT p1+    unU $ runIFreeT $ case x1 of+        Wrap (Close   p1') -> wrap $ Close p1'+        Wrap (Yield c p1') -> wrap $ Yield c (p1' <~< p2)+        Wrap (Await   f1 ) -> IFreeT $ U $ do+            x2 <- unU $ runIFreeT p2+            let p1' = IFreeT $ returnI x1+            unU $ runIFreeT $ case x2 of+                Wrap (Close p2')   -> wrap $ Close $ p1' <~| p2'+                Wrap (Yield b p2') -> f1 b <~< p2'+                Wrap (Await f2) -> wrap $ Await $ fmap (\p2'-> p1' <~< p2') f2++(<~|) :: (Monad m)+ => IFreeT (FrameF c) (U m) (r := C) (O b)+ -> IFreeT (FrameF b) (U m) (r := C)  C+ -> IFreeT (FrameF c) (U m) (r := C)  C+p1 <~| p2 = IFreeT $ U $ do+    x1 <- unU $ runIFreeT p1+    unU $ runIFreeT $ case x1 of+        Wrap (Close   p1') -> p1'+        Wrap (Yield c p1') -> wrap $ Yield c (p1' <~| p2)+        Wrap (Await   f1 ) -> IFreeT $ U $ do+            x2 <- unU $ runIFreeT p2+            let p1' = IFreeT $ returnI x1+            unU $ runIFreeT $ case x2 of+                Return r           -> returnI r+                Wrap (Yield b p2') -> f1 b <~| p2' ++heap :: (Monad m)+ => m ()+ -> IFreeT (FrameF (m (), c)) (U m) (r := C) (M        b )+ -> IFreeT (FrameF (m (), c)) (U m) (r := C) (M (m (), b))+heap m p = IFreeT $ U $ do+    x <- unU $ runIFreeT p+    unU $ runIFreeT $ case x of+        Wrap (Close         p') -> wrap $ Close $ liftU m !> p'+        Wrap (Yield (m', c) p') -> wrap $ Yield (m >> m', c) (heap m p')+        Wrap (Await         f ) -> wrap $ Await $ \e -> case e of+            Nothing      -> heap (return ()) (f  Nothing)+            Just (m', b) -> heap m'          (f $ Just b)++stack :: (Monad m)+ => Bool+ -> IFreeT (FrameF        b ) (U m) (r := C) (M a)+ -> IFreeT (FrameF (Maybe b)) (U m) (r := C) (M a)+stack t p = IFreeT $ U $ do+    x <- unU $ runIFreeT p+    unU $ runIFreeT $ case x of+        Wrap (Close   p') -> wrap $ Close $ warn p'+        Wrap (Yield b p') -> wrap $ Yield (Just b) (stack t p')+        Wrap (Await   f ) ->+            let p' = wrap $ Await $ \e -> stack (isNothing e) (f e)+             in case t of+                    False -> p'+                    True  -> wrap $ Yield Nothing p'++warn :: (Monad m)+ => IFreeT (FrameF        b ) (U m) (r := C) C+ -> IFreeT (FrameF (Maybe b)) (U m) (r := C) C+warn p = IFreeT $ U $ do+    x <- unU $ runIFreeT p+    unU $ runIFreeT $ case x of+        Return r -> wrap $ Yield Nothing (returnI r)+        Wrap (Yield b p') -> wrap $ Yield (Just b) (warn p')++{- $compose+    The fourth step to convert 'Pipe' code to 'Frame' code is to replace ('<+<')+    with ('<-<'):++> printer <-< take' 3 <-< fromList [1..]++    Like 'Pipe's, Frames form a 'Category' where composition pipes the output+    from the upstream 'Frame' to the input of the downstream 'Frame'.+    Additionally, composition guarantees the following behaviors:++    * 'Frame's receive exactly one 'Nothing' if an upstream 'Frame' terminates.++    * Registered finalizers get called exactly once if a downstream 'Frame'+      terminates.++    * Finalizers are always ordered from upstream to downstream.++    The 'Category' laws cannot be broken, so you don't have to be careful when+    using 'Frame's.++    Note that you may only compose 'Frame's that begin open and end closed.+-}++-- | Corresponds to ('<<<')/('.') from @Control.Category@+(<-<) :: Monad m+ => Frame c m (M b) C r -> Frame b m (M a) C r -> Frame c m (M a) C r+p1 <-< p2 = heap (return ()) p1 <~< stack False p2++-- | Corresponds to ('>>>') from @Control.Category@+(>->) :: Monad m+ => Frame b m (M a) C r -> Frame c m (M b) C r -> Frame c m (M a) C r+(>->) = flip (<-<)++infixr 9 <-<+infixr 9 >->++-- | Corresponds to 'id' from @Control.Category@+idF :: (Monad m) => Frame a m (M a) C r+idF = foreverR $ await !>= yield++-- | 'Frame's form a 'Category' instance when you rearrange the type variables+newtype FrameC m r a b = FrameC { unFrameC :: Frame b m (M a) C r }++instance (Monad m) => Category (FrameC m r) where+    id = FrameC idF+    (FrameC p1) . (FrameC p2) = FrameC (p1 <-< p2)++{- $run+    The fifth step to convert 'Pipe' code to 'Frame' code is to use 'runFrame'+    instead of 'runPipe':++>>> runFrame $ printer <-< take' 3 <-< fromList [1..]+1+2+3+fromList interrupted+You shall not pass!+printer interrupted+>>> runFrame $ printer <-< take' 3 <-< fromList [1]+1+You shall not pass!+take' interrupted+printer interrupted++-}++{-|+    Run the 'Frame' monad transformer, converting it back to the base monad.++    'runFrame' is the 'Frame' equivalent to 'runPipe' and requires a+    self-contained 'Stack'.+-}+runFrame :: (Monad m) => Stack m r -> m r+runFrame p = do+    x <- unU $ runIFreeT p+    case x of+        Wrap (Close   p') -> runFrame' p'+        Wrap (Yield _ p') -> runFrame  p'+        Wrap (Await   f ) -> runFrame (f $ Just ())++runFrame' :: (Monad m) => Frame Void m C C r -> m r+runFrame' p = do+    x <- unU $ runIFreeT p+    case x of+        Return (V r)      -> return r+        Wrap (Yield _ p') -> runFrame'  p'
+ Control/Frame/Tutorial.hs view
@@ -0,0 +1,487 @@+{-|+    This module provides the tutorial for "Control.Frame".+-}++module Control.Frame.Tutorial (+    -- * Restricted Monads+    -- $restrict1++    -- $extension++    -- $restrict2++    -- * Type Signatures+    -- $types++    -- * Prompt Finalization+    -- $prompt++    -- * Composition+    -- $compose++    -- * Finalization+    -- $ensure++    -- * Folds+    -- $fold++    -- * Strictness+    -- $strict++    -- * Robustness+    -- $robust+    ) where++-- For documentation+import Control.Category+import Control.Frame+import Control.IMonad+import Control.IMonad.Trans+import Control.Monad.Trans.Class+import Control.Pipe hiding (await, yield, Await, Yield)++{- $restrict1+    'Frame's extend 'Pipe's with two new features:++    * Folding input and intercepting upstream termination++    * Guaranteeing prompt and deterministic finalization++    However, these extra features comes with some added complexity: restricted+    monads, also known as indexed monads.  Restricted monads sound scarier than+    they are, so I'll demonstrate that if you are comfortable using monads, then+    you'll be comfortable using restricted monads.++    Let's translate the @take'@ function from the 'Pipe's tutorial into a+    'Frame' to see what changes when we use restricted monads:++-}+-- $extension+-- > {-# LANGUAGE RebindableSyntax #-}+-- >+-- > import Control.Frame+-- > import Control.IMonad.Do+-- > import Control.IMonad.Trans+-- > import Prelude hiding (Monad(..))+-- >+-- > take' :: Int -> Frame a IO (M a) C ()+-- > take' n = do+-- >     replicateMR_ n $ do+-- >         x <- await+-- >         yield x+-- >     close+-- >     liftU $ putStrLn "You shall not pass!"+{- $restrict2+    This time I included all imports and highlighted the new @RebindableSyntax@+    extension.  The new imports belong to the @Control.IMonad@ hierarchy from+    the @index-core@ package, which provides the core restricted monad+    functionality.++    Yet, you almost wouldn't even know you were using an restricted monad just+    by looking at the code.  This is because @index-core@ can rebind @do@+    notation to use restricted monads instead of ordinary extensions.  Three+    things make this possible:++    * The @RebindableSyntax@ extension, which allows libraries to override+      @do@ syntax (among other things)++    * The @Control.IMonad.Do@ module which exports the new bindings for @do@+      notation++    * Hiding 'Monad' from the Prelude so that it does not conflict with the+      bindings from @index-core@++    However, you are not obligated to rebind @do@ notation to use 'Frame's.  You+    can choose to keep ordinary @do@ notation and desugar the restricted monad+    by hand.  Just import @Control.IMonad@ instead, drop the @RebindableSyntax@+    extension, and don't hide 'Monad'.  Then you can desugar @take'@ manually+    using the restricted monad operators:++> import Control.Frame+> import Control.IMonad+> import Control.IMonad.Trans+>+> take' :: Int -> Frame a IO (M a) C ()+> take' n =+>     (replicateMR_ n $+>         await !>= \x -> +>         yield x) !>= \_ ->+>     close        !>= \_ ->+>     liftU $ putStrLn "You shall not pass!"++    However, for this tutorial I will use the @do@ notation, since it's prettier+    and easier to use.++    You'll also notice functions that resemble the ones in @Control.Monad@,+    except with an \'@R@\' suffix on the end of them, like 'replicateMR_'.+    Most functions in @Control.Monad@ have a restricted counterpart provided by+    @Control.IMonad.Restrict@ (which is in turn re-exported by+    @Control.IMonad@), such as 'whenR', 'foreverR', and 'mapMR'.++    Also, every time you lift an operation from the base monad, you must use+    'liftU' instead of 'lift'.  'Frame's are \"restricted monad transformers\",+    and they would normally lift a base restricted monad using 'liftI', but+    they can also lift ordinary monads, too, using 'liftU' (mnemonic: \"lift\"+    an ordinary monad and \'U\'pgrade it to a restricted monad).+-}++{- $types+    The 'Frame' type constructor also looks a bit different, too:++> Frame a IO (M a) C ()++    Let's dissect that to understand how 'Frame's work:++>       | Output | Base monad | Initial Input | Final Input | Return Value+> Frame   a        IO           (M a)           C             ()++    'Frame's differ from 'Pipe's in that their input end indexes the beginning+    and end of the operation.  Our @take'@ function starts off with an open+    input end (@M a@), and ends with a closed input end (@C@).++    @take'@ finishes with a closed input end because it called the 'close'+    function, which seals off and finalizes upstream.  You can see that the+    'close' primitive changes the index just by looking at its type:++> close :: Monad m => Frame b m (M a) C ()++    The 'close' instruction begins with an open input end (@M a@) and finishes+    with a closed input end (@C@).  If you tried to call 'close' twice, you'd+    get a type error:++> -- wrong!+> do close+>    close++    This prevents you from accidentally finalizing upstream twice.++    'close' is the only primitive that changes the index, and there is no way to+    reopen the input once you have closed it.  'close' also forbids you from+    'await'ing input from upstream after you have already closed it.  If you+    try, you will get a type error++> -- wrong!+> do close+>    await++    This prevents you from requesting input from a finalized pipe.  In fact,+    once you 'close' your input end, every upstream 'Frame' disappears+    completely.  You couldn't get input from upstream anyway, even if you+    somehow allowed 'await' statements after 'close'.++    You can check out 'await''s type signature to see why it won't type-check+    after 'close':++> await :: Monad m => Frame b m (M a) (M a) a++    'await' must begin with the input end open (@M a@) and it leaves the input+    end open when done (@M a@).  However, you can still use a 'yield' anywhere:++> yield :: Monad m => b -> Frame b m i i ()++    'yield' will work whether or not the input end is open, and it leaves the+    input end in the same state once 'yield' is done.+-}++{- $prompt+    Every 'Frame' must close its input end /exactly/ one time before you can+    compose it with other 'Frame's.  The only exception is if a 'Frame' never+    terminates:++> -- This type-checks because foreverR is polymorphic in the final index+> printer :: (Show b) => Frame Void IO (M b) C r+> printer = foreverR $ do+>     a <- await+>     liftU $ print a++    However, when a 'Frame' no longer needs input then you should 'close' it as+    early as possible.  The earlier you 'close' upstream, the more promptly+    upstream gets finalized.++    If you write a stand-alone producer from start to finish, you can be sure it+    will never need upstream, so you can close it immediately:++> -- I'm keeping fromList's input end polymorphic for a later example+> fromList :: (M.Monad m) => [b] -> Frame b m (M a) C ()+> fromList xs = do+>     close+>     mapMR_ yield xs++    However, if @fromList@ were a library function, you would remove the 'close'+    statement as you cannot guarantee that your user won't want to 'await' after+    @fromList@.  Or, the user might want to call @fromList@ twice within the+    same 'Frame', and having two close statements would lead to a type error.+    Therefore, a good rule of thumb when writing library code for 'Frame's is to+    always let the user decide when to 'close' the 'Frame' unless you are+    writing a stand-alone 'Frame'.++    So for right now, I will leave the 'close' in @fromList@ for simplicity and+    treat it as a stand-alone 'Frame'.  Also, it will come in handy for a later+    example.+-}++{- $compose+    Composition works just like 'Pipe's, except you use the ('<-<') composition+    operator instead of ('<+<'):++> stack :: Stack IO ()+> stack = printer <-< take' 3 <-< fromList [1..]++    The 'Frame' equivalent to 'Pipeline' is a 'Stack' (mnemonic: call stack;+    also the name 'Frame' refers to a call stack frame):++> type Stack m r = Frame Void m (M ()) C r++    Similarly, you use 'runFrame' instead of 'runPipe' to convert the 'Frame'+    back to the base monad:++>>> runFrame stack+1+2+3+You shall not pass!++    However, let's carefully inspect the type of composition:++> (<-<) :: Monad m+>  => Frame c m (M b) C r+>  -> Frame b m (M a) C r+>  -> Frame c m (M a) C r++    Each argument 'Frame' must begin in an open state and end in a closed state.+    This means that each 'Frame' in a 'Stack' must call 'close' exactly once+    before it may be used.  'runFrame' has the exact same restriction:++> runFrame :: Monad m => Stack m r -> m r+> runFrame ~  Monad m => Frame Void m (M ()) C r -> m r++    Composition specifically requires the user to define when to finalize+    upstream and does not assume this occurs at the end of the 'Frame'.  This+    doesn't pose a problem for stand-alone 'Frame's, since they will know when+    they no longer need input, but smaller library components designed to be+    assembled into larger 'Frame's should let the user decide at the very last+    moment where to 'close' the 'Pipe'.  There is no way to know ahead of time+    where the 'close' should be until the complete 'Frame' has been assembled.+-}++{- $ensure+    With 'Frame's in hand, we can now write a safe @read'@ function:++> readFile' :: Handle -> Frame Text IO C C ()+> readFile' h = do+>     eof <- liftU $ hIsEOF h+>     whenR (not eof) $ do+>         s <- liftU $ hGetLine h+>         yield s+>         readFile' h+> +> read' :: FilePath -> Frame Text IO C C ()+> read' file = do+>     liftU $ putStrLn "Opening file..."+>     h <- liftU $ openFile file ReadMode+>     -- The following requires "import qualified Control.Monad as M"+>     finallyD (putStrLn "Closing file ..." M.>> hClose h) $ readFile' h++    The 'finallyD' function registers a block-level finalizer that executes if a+    downstream 'Pipe' terminates or if the block completes normally.  The more+    general 'finallyF' function will call the finalizer if /any/ 'Frame'+    terminates.++    Usually you would always want to use 'finallyF', but because of some type+    limitations you can only use 'finallyD' after a 'Frame' is closed.  A future+    release of this library will fix this and merge 'finallyD' into 'finallyF'.+    So that means that for everything beginning before a 'close' statement, use+    'finallyF', otherwise use 'finallyD'.++    Similarly, you can use the 'catchF' / 'catchD' counterparts to the+    \"finally\" functions.  The \"catch\" functions run the finalizer only if+    another 'Frame' terminates before the block is done, but not if the block+    terminates normally.++    We don't 'close' the @read'@ function because it's not a stand-alone+    'Frame'.  We want to be able to concatenate multiple @read'@s together+    within the same 'Frame', like so:++> files = do+>     close+>     read' "file1.txt"+>     read' "file2.txt"++    So let's assume those two files have the following contents:++    \"@file1.txt@\"++> Line 1+> Line 2+> Line 3++    \"@file2.txt@\"++> A+> B+> C++    We can now check to see if our @files@ producer works:++>>> runFrame $ printer <-< files+Opening file...+"Line1"+"Line2"+"Line3"+Closing file ...+Opening file...+"A"+"B"+"C"+Closing file ...++    More importantly, files are never opened if they aren't demanded and they+    are always properly finalized if the consumer terminates early:++>>> runFrame $ printer <-< take' 2 <-< files+Opening file...+"Line1"+"Line2"+Closing file ...+You shall not pass!++    So we get lazy, deterministic, and prompt resource management.  Nice!++-}++{- $fold+    'Frame's can actually do more than just manage finalization!  Using+    'Frame's, we can now correctly implement folds like @toList@ in a way that+    is truly compositional:++> toList :: (M.Monad m) => Frame b m (M a) (M a) [a]+> toList = do+>     a' <- awaitF+>     case a' of+>         Nothing -> return []+>         Just a  -> do+>             as <- toList+>             return (a:as)++    We used one new function this time: 'awaitF'.  This is like 'await' except+    that it returns a 'Nothing' if upstream terminates before 'yield'ing back a+    value.  This allows you to intercept upstream termination and do some+    cleanup, and in our case we use it to end the fold.++    You only receive a 'Nothing' once when you use 'awaitF'.  Any attempt to+    request more input after you receive the first 'Nothing' will terminate the+    current 'Frame' using the upstream return value.  In fact, 'await' is built+    on top of 'awaitF':++> await = do+>     a' <- awaitF+>     case a' of+>         Nothing -> await+>         Just a  -> return a++    If it gets a 'Nothing', it just ignores it and 'await's again, choosing to+    not do any cleanup.++    Now let's make sure our @toList@ function works.  I didn't make @toList@ a+    stand-alone 'Frame', so we will have to include a 'close' statement to+    complete it before composing it:++> p1 = do+>     xs <- toList+>     close+>     return (Just xs)+>+> p2 xs = do+>     fromList xs+>     return Nothing -- Remember: they need the same return type++>>> runFrame $ p1 <-< p2 [1..10]+Just [1,2,3,4,5,6,7,8,9,10]+-}++{- $strict+    Lazy resource management has one important disadvantage: we can't free the+    resource until downstream no longer needs input.  Many libraries duplicate+    their code to provide Lazy and Strict versions, allowing the user to decide+    if they want:++    * Lazy input, which conserves memory, but holds onto the resource until+      downstream is done processing it++    * Strict input, which loads everything into memory, but can then immediately+      dispose of the resource before the input is processed++    What if there were a way to seamlessly switch between those semantics or+    even choose something in between?  Well, it turns out we can!++    First, we can combine @fromList@ and @toList@ into something even cooler:++> strict :: (M.Monad m) => Frame a m (M a) C ()+> strict = do+>     xs <- toList+>     fromList xs++    As the name suggests, the @strict@ function is strict in its input.+    @strict@ loads the entire input into memory, finalizes upstream, then+    proceeds to hand the input off to downstream.  We can prove this just by+    using it:++>>> runFrame $ printer <-< strict <-< files+> Opening file...+> Closing file ...+> Opening file...+> Closing file ...+> "Line1"+> "Line2"+> "Line3"+> "A"+> "B"+> "C"++    Both files were disposed of immediately, at the expense of using more+    memory.++    But what if we want something in between strictness and laziness?  Maybe +    something like this:++>>> runFrame $ printer <-< strict <-< take' 2 <-< files+Opening file...+Closing file ...+You shall not pass!+"Line1"+"Line2"++    Now we have the best of both worlds.  We can pick and choose how much of+    our source to strictly load into memory.  In the above example, we specified+    that we wanted to be strict only in the first two lines of our input, and as+    a result the third line of \"@file1.txt@\" is never read and \"@file2.txt@\"+    is never even opened!++    Now we have a way to seamlessly slide anywhere on the spectrum between+    laziness and strictness, and it's all implemented entirely within Haskell+    in a way that is elegant and intuitive without the use of artificial and+    clumsy 'seq' annotations.+-}++{- $robust+    The 'Frame' implementation exposes all internals, yet this does not+    compromise safety or invariants in any way.  The library's implementation is+    \"correct-by-construction\", meaning that you can extend it with your own+    features if you so choose, and you never have to worry about accidentally+    breaking any laws, such as the associativity of composition.++    This has the following important practical benefits for finalization and+    folds:++    * Finalizers never get duplicated or dropped++    * Folds can be performed anywhere within the 'Stack', not just at the most+      downstream 'Frame', as the @strict@ example illustrates.++    * You can reason about each 'Frame's finalization behavior completely+      independently of other 'Frame's.++    Composition elegantly handles every single corner case.  This directly+    follows from strictly enforcing the 'Category' laws, because categories have+    no corners!+-}
+ Control/IMonad/Trans/Free.hs view
@@ -0,0 +1,56 @@+-- | This module is the indexed version of "Control.Monad.Trans.Free"++{-# LANGUAGE KindSignatures, TypeOperators #-}++module Control.IMonad.Trans.Free (+    -- * Free monad transformers+    -- $freet+    IFreeF(..),+    IFreeT(..),+    wrap,+    liftF+    ) where++import Control.Category.Index+import Control.IMonad+import Control.IMonad.Trans++{- $freet+    Indexed free monad transformers lift the constructor signatures to+    the category of indexed Haskell functions: (':->').++> Return ::   r :-> IFreeF f r x+> Wrap   :: f x :-> IFreeF f r x+>+> IFreeT :: m (IFreeF f r (IFreeT f m r)) :-> IFreeT f m r+-}++-- | Indexed equivalent to @FreeF@+data IFreeF f r (x :: * -> *) i = Return (r i) | Wrap (f x i)++-- | Indexed equivalent to @FreeT@+data IFreeT f m r i = IFreeT { runIFreeT :: m (IFreeF f r (IFreeT f m r)) i }++instance (IFunctor f, IMonad m) => IFunctor (IFreeT f m) where+    fmapI f x = x ?>= returnI . f++instance (IFunctor f, IMonad m) => IMonad (IFreeT f m) where+    returnI = IFreeT . returnI . Return+    bindI f m = IFreeT $+        runIFreeT m ?>= \x ->+        runIFreeT $ case x of+            Return r -> f r+            Wrap   w -> wrap $ fmapI (bindI f) w++instance (IFunctor f) => IMonadTrans (IFreeT f) where+    liftI = IFreeT . fmapI Return++-- | Indexed equivalent to @wrap@+wrap :: (IMonad m) => f (IFreeT f m r) :-> IFreeT f m r+wrap = IFreeT . returnI . Wrap++-- | Indexed equivalent to @liftF@+liftF :: (IFunctor f, IMonad m) => f r :-> IFreeT f m r+liftF x = wrap $ fmapI returnI x++-- FIXME: Add IIdentity so that IFree can be defined in terms of IFreeT
Control/Monad/Trans/Free.hs view
@@ -1,19 +1,29 @@-{-| Every functor @f@ gives rise to a corresponding free monad: @Free f@.--    A free monad over a functor resembles a \"list\" of that functor:+{-|+    People commonly misconstrue 'Free' as defining a monad transformer with+    'liftF' behaving like 'lift', however that approach violates the monad+    transformer laws.  Another common mistake is to include the base monad as a+    term in the functor, which also gives rise to an incorrect monad+    transformer. -    * 'pure' behaves like @[]@ by not using the functor at all+    To solve this, this module provides 'FreeT', which properly generalizes the+    free monad to a free monad transformer which is correct by construction. -    * 'wrap' behaves like @(:)@ by prepending another layer of the functor+    The 'FreeT' type commonly arises in coroutine and iteratee libraries that+    wish to provide a monad transformer that correctly obeys the monad+    transformer laws. -}+ module Control.Monad.Trans.Free (-    -- * The Free monad+    -- * Free monad transformer+    -- $freet     FreeF(..),-    Free(..),-    wrap,-    runFree,-    -- * The FreeT monad transformer     FreeT(..),+    wrap,+    liftF,+    -- * Free monad+    -- $free+    Free,+    runFree     ) where  import Control.Applicative@@ -21,57 +31,84 @@ import Control.Monad.Trans.Class import Data.Functor.Identity -data FreeF f r x = Pure r | Wrap (f x)--{-|-    The 'Free' type is isomorphic to:+{- $freet+    This differs substantially from the non-monad-transformer version because+    of the requirement to nest the constructors within the base monad. -> data Free f r = Pure r | Wrap (f (Free f r))+    To deconstruct a free monad transformer, use 'runFreeT' to unwrap it and+    bind the result in the base monad.  You can then pattern match against the+    bound value to obtain the next constructor: -    ... except that if you want to pattern match against those constructors, you-    must first use 'runFree' to unwrap the value first.+> do x <- runFreeT f+>    case x of+>        Return r -> ...+>        Wrap   w -> ... -    Similarly, you don't use the raw constructors to build a value of type-    'Free'.  You instead use the smart constructors 'pure' (from-    @Control.Applicative@) and 'wrap'.+    Because of this, you cannot create free monad transformers using the raw+    constructors from 'FreeF'.  Instead you use the smart constructors 'return'+    (from @Control.Monad@) and 'wrap'. -}-type Free f = FreeT f Identity -wrap :: (Monad m) => f (FreeT f m r) -> FreeT f m r-wrap = FreeT . return . Wrap--runFree :: Free f r -> FreeF f r (Free f r)-runFree = runIdentity . runFreeT+-- | The signature for 'Free'+data FreeF f r x = Return r | Wrap (f x)  {-|-    A free monad transformer alternates nesting the base functor @f@ and the-    base monad @m@.+    A free monad transformer alternates nesting the base monad @m@ and the base+    functor @f@. -    * @f@ - The functor that generates the free monad+    * @f@ - The functor that generates the free monad transformer      * @m@ - The base monad      * @r@ - The type of the return value--    This type commonly arises in coroutine/iteratee libraries under various-    names. -} data FreeT f m r = FreeT { runFreeT :: m (FreeF f r (FreeT f m r)) } -instance (Functor f, Monad m) => Monad (FreeT f m) where-    return = FreeT . return . Pure-    m >>= f = FreeT $ do-        x <- runFreeT m-        runFreeT $ case x of-            Pure r -> f r-            Wrap a -> wrap $ fmap (>>= f) a- instance (Functor f, Monad m) => Functor (FreeT f m) where     fmap = liftM  instance (Functor f, Monad m) => Applicative (FreeT f m) where-    pure = return+    pure  = return     (<*>) = ap +instance (Functor f, Monad m) => Monad (FreeT f m) where+    return  = FreeT . return . Return+    m >>= f = FreeT $ do+        x <- runFreeT m+        runFreeT $ case x of+            Return r -> f r+            Wrap   w -> wrap $ fmap (>>= f) w+ instance MonadTrans (FreeT f) where-    lift = FreeT . liftM Pure+    lift = FreeT . liftM Return++-- | Smart constructor for 'Wrap'+wrap :: (Monad m) => f (FreeT f m r) -> FreeT f m r+wrap = FreeT . return . Wrap++-- | Equivalent to @liftF@ from "Control.Monad.Free"+liftF :: (Functor f, Monad m) => f r -> FreeT f m r+liftF x = wrap $ fmap return x++{- $free+    The 'Free' type is isomorphic to the following simple implementation:++> data Free f r = Return r | Wrap (f (Free f r))++    ... except that if you want to pattern match against those constructors, you+    must first use 'runFree' to unwrap the value first.++> case (runFreeT f) of+>     Return r -> ...+>     Wrap   w -> ...++    Similarly, you use the smart constructors 'return' and 'wrap' to build a+    value of type 'Free'.+-}++-- | 'FreeT' reduces to 'Free' when specialized to the 'Identity' monad.+type Free f = FreeT f Identity++-- | Observation function that exposes the next 'FreeF' constructor+runFree :: Free f r -> FreeF f r (Free f r)+runFree = runIdentity . runFreeT
Control/Pipe.hs view
@@ -1,764 +1,273 @@-module Control.Pipe (-    -- * Types-    -- $type--    -- * Composition-    -- $compose--    -- * Modularity-    -- $modular--    -- * Vertical Concatenation-    -- $vertical--    -- * Return Values-    -- $return--    -- * Termination-    -- $terminate--    -- * Resource Management-    -- $resource--    -- * Frames-    -- $frame--    -- * Frame Composition-    -- $framecompose--    -- * Frame vs. Ensure-    -- $frameensure--    -- * Folds-    -- $fold+{-|+    'Pipe' is a monad transformer that enriches the base monad with the ability+    to 'await' or 'yield' data to and from other 'Pipe's.+-} -    -- * Strictness-    -- $strict+module Control.Pipe (+    -- * Introduction+    -- $summary -    module Control.Pipe.Common,-    module Control.Pipe.Final+    -- * Types+    -- $types+    PipeF(..),+    Pipe,+    Producer,+    Consumer,+    Pipeline,+    -- * Create Pipes+    -- $create+    await,+    yield,+    pipe,+    -- * Compose Pipes+    -- $category+    (<+<),+    (>+>),+    idP,+    PipeC(..),+    -- * Run Pipes+    -- $runpipe+    runPipe     ) where +import Control.Applicative import Control.Category-import Control.Monad.Trans.Class-import Control.Pipe.Common-import Control.Pipe.Final-import Data.Void--{- $type-    This library represents streaming computations using a single data type:-    'Pipe'.--    'Pipe' is a monad transformer that extends the base monad with the ability-    to 'await' input from or 'yield' output to other pipes.  Pipes resemble-    enumeratees in other libraries because they receive an input stream and-    transform it into a new output stream.--    I'll introduce our first 'Pipe', which is a verbose version of the Prelude's-    'take' function:--> take' :: Int -> Pipe a a IO ()-> take' n = do->     replicateM_ n $ do->         x <- await->         yield x->     lift $ putStrLn "You shall not pass!"--    This pipe forwards the first @n@ values it receives undisturbed, then it-    outputs a cute message.--    Let's dissect the above pipe's type to learn a bit about how pipes work:-->      | Input Type | Output Type | Base monad | Return value-> Pipe   a            a             IO           ()--    So @take'@ 'await's input values of type @a@ from upstream pipes and-    'yield's output values of type @a@ to downstream pipes.  @take'@ uses 'IO'-    as its base monad because it invokes the 'putStrLn' function.  If we were to-    remove the call to 'putStrLn', the compiler would infer the following type-    instead, which is polymorphic in the base monad:--> take' :: (Monad m) => Int -> Pipe a a m ()--    Now let's create a function that converts a list into a pipe by 'yield'ing-    each element of the list:--> fromList :: (Monad m) => [b] -> Pipe a b m ()-> fromList = mapM_ yield--    Note that @fromList xs@ is polymorphic in its input.  This is because it-    does not 'await' any input.  If we wanted, we could type-restrict it to:--> fromList :: (Monad m) => [b] -> Pipe () b m ()--    There is no type that forbids a pipe from 'await'ing, but you can guarantee-    that if it does 'await', the request is trivially satisfiable by supplying-    it with @()@.--    A pipe that doesn't 'await' (any useful input) can serve as the first stage-    in a 'Pipeline'.  I provide a type synonym for this common case:--> type Producer b m r = Pipe () b m r--    'Producer's resemble enumerators in other libraries because they function as-    data sources.--    You can then use the 'Producer' type synonym to rewrite the type signature-    for @fromList@ as:--> fromList :: (Monad m) => [b] -> Producer b m ()--    Now let's create a pipe that prints every value delivered to it:--> printer :: (Show b) => Pipe b c IO r-> printer = forever $ do->     x <- await->     lift $ print x--    Here, @printer@ is polymorphic in its output.  We could type-restrict it to-    guarantee it will never 'yield' by setting the output to 'Void', from-    @Data.Void@:--> printer :: (Show a) => Pipe b Void IO r--    A pipe that never yields can be the final stage in a 'Pipeline'.  Again,-    I provide a type synonym for this common case:--> type Consumer b m r = Pipe b Void m r--    So we could instead write @printer@'s type as:+import Control.Monad (forever)+import Control.Monad.Trans.Class (lift)+import Control.Monad.Trans.Free+import Data.Void (Void)+import Prelude hiding ((.), id) -> printer :: (Show b) => Consumer b IO r+{- $summary+    I completely expose the 'Pipe' data type and internals in order to encourage+    people to write their own 'Pipe' functions.  This does not compromise the+    correctness or safety of the library at all and you can feel free to use the+    constructors directly without violating any laws or invariants. -    'Consumer's resemble iteratees in other libraries because they function as-    data sinks.+    I promote using the 'Monad' and 'Category' instances to build and compose+    pipes, but this does not mean that they are the only option.  In fact, any+    combinator provided by other iteratee libraries can be recreated for pipes,+    too.  However, this core library does not provide many of the functions+    found in other libraries in order to encourage people to find principled and+    theoretically grounded solutions rather than devise ad-hoc solutions+    characteristic of other iteratee implementations. -} -{- $compose-    What distinguishes pipes from every other iteratee implementation is that-    they form a true 'Category'.  Because of this, you can literally compose-    pipes into 'Pipeline's using ordinary composition:--> newtype Lazy m r a b = Lazy { unLazy :: Pipe a b m r }-> instance Category (Lazy m r) where ...--    For example, you can compose the above pipes with:--> pipeline :: Pipe () Void IO ()-> pipeline = unLazy $ Lazy printer . Lazy (take' 3) . Lazy (fromList [1..])--    The compiler deduces that the final pipe must be blocked at both ends,-    meaning it will never 'await' useful input and it will never 'yield' any-    output.  This represents a self-contained 'Pipeline' and I provide a type-    synonym for this common case:--> type Pipeline m r = Pipe () Void m r--    Also, I provide '<+<' as a convenience operator for composing pipes without-    the burden of wrapping and unwrapping newtypes:--> p1 <+< p2 = unLazy $ Lazy p1 . Lazy p2--    So you can rewrite @pipeline@ as:--> pipeline :: Pipeline IO ()-> pipeline = printer <+< take' 3 <+< fromList [1..]--    Like many other monad transformers, you convert the 'Pipe' monad back to the-    base monad using some sort of \"@run...@\" function.  In this case, it's the-    'runPipe' function:--> runPipe :: (Monad m) => Pipeline m r -> m r--    'runPipe' only works on self-contained 'Pipeline's, but you don't need to-    worry about explicitly type-restricting any of your pipes.  Self-contained-    pipelines will automatically have polymorphic input and output ends and they-    will type-check when you provide them to 'runPipe'.--    Let's try using 'runPipe':-->>> runPipe pipeline-1-2-3-You shall not pass!--    Fascinating!  Our pipe terminates even though @printer@ never terminates-    and @fromList@ never terminates when given an infinite list.  To illustrate-    why our pipe terminates, let's outline the pipe flow control rules for-    composition:--    * Pipes are lazy, so execution begins at the most downstream pipe-      (@printer@ in our example).--    * Upstream pipes only run if input is requested from them and they only run-      as long as necessary to 'yield' back a value.--    * If a pipe terminates, it terminates every other pipe composed with it.--    Another way to think of this is like a stack where each pipe is a frame on-    that stack:--    * If a pipe 'await's input, it blocks and pushes the next pipe upstream onto-      the stack until that pipe 'yield's back a value.--    * If a pipe 'yield's output, it pops itself off the stack and restores-      control to the original downstream pipe that was 'await'ing its input.-      This binds its result to the return value of the pending 'await' command.--    All of these flow control rules uniquely follow from the 'Category' laws.--    It might surprise you that termination brings down the entire pipeline until-    you realize that:--    * Downstream pipes depending on the terminated pipe cannot proceed--    * Upstream pipes won't be further evaluated because the terminated pipe will-      not request any further input from them--    So in our previous example, the 'Pipeline' terminated because @take' 3@-    terminated and brought down the entire 'Pipeline' with it.--    Actually, these flow control rules will mislead you into thinking that-    composed pipes behave as a collection of sub-pipes with some sort of message    passing architecture between them, but nothing could be further from the-    truth! When you compose pipes, they automatically fuse into a single pipe-    that corresponds to how you would have written the control flow by hand.--    For example, if you compose @printer@ and @fromList@:--> printer <+< fromList [1..]--    The result is indistinguishable from:--> lift (mapM_ print [1..])+{- $types+    The 'Pipe' type is strongly inspired by Mario Blazevic's @Coroutine@ type in+    his concurrency article from Issue 19 of The Monad Reader and is formulated+    in the exact same way. -    ... which is what we would have written by hand if we had not used pipes at-    all!  All 'runPipe' does is just remove the 'lift'!+    His @Coroutine@ type is actually a free monad transformer (i.e. 'FreeT')+    and his @InOrOut@ functor corresponds to 'PipeF'. -} -{- $modular-    Given a loop like:--> loop :: IO r-> loop = forever $ do->     x <- dataSource->     y <- processData x->     dataSink y--    We could decompose it into three separate parts:--> stage1 :: Producer a IO r-> stage1 = forever $ do->     x <- dataSource->     yield x->-> stage2 :: Pipe a b IO r-> stage2 = forever $ do->     x <- await->     y <- processData x->     yield y->->-> stage3 :: Consumer b IO r-> stage3 = forever $ do->     y <- await->     dataSink->-> stage3 <+< stage2 <+< stage1 == lift loop+-- | The base functor for the 'Pipe' type+data PipeF a b x = Await (a -> x) | Yield (b, x) -    In other words, pipes let you decompose loops into modular components, which-    promotes loose coupling and allows you to freely mix and match those-    components.+-- I could use the "DerivingFunctor" extension, but I want to remain portable+instance Functor (PipeF a b) where+    fmap f (Await a) = Await $ fmap f a+    fmap f (Yield y) = Yield $ fmap f y -    To demonstrate this, let's define a new data source that indefinitely-    prompts the user for integers:+{-|+    The base type for pipes -> prompt :: Producer Int IO a-> prompt = forever $ do->     lift $ putStrLn "Enter a number: "->     n <- read <$> lift getLine->     yield n+    * @a@ - The type of input received from upstream pipes -    Now we can use it as a drop-in replacement for @fromList@:+    * @b@ - The type of output delivered to downstream pipes ->>> runPipe $ printer <+< take' 3 <+< prompt-Enter a number:-1<Enter>-1-Enter a number:-2<Enter>-2-Enter a number:-3<Enter>-3-You shall not pass!+    * @m@ - The base monad +    * @r@ - The type of the return value -}--{- $vertical-    You can easily \"vertically\" concatenate pipes, 'Producer's, and-    'Consumer's, all using simple monad sequencing: ('>>').  For example, here-    is how you concatenate 'Producer's:-->>> runPipe $ printer <+< (fromList [1..3] >> fromList [10..12])-1-2-3-10-11-12+type Pipe a b = FreeT (PipeF a b) -    Here's how you would concatenate 'Consumer's:+-- | A pipe that produces values+type Producer b = Pipe () b ->>> let print' n = printer <+< take' n :: (Show a) => Int -> Consumer a IO ()->>> runPipe $ (print' 3 >> print' 4) <+< fromList [1..]-1-2-3-You shall not pass!-4-5-6-7-You shall not pass!+-- | A pipe that consumes values+type Consumer b = Pipe b Void -   ... but the above example is gratuitous because we could have just-   concatenated the intermediate @take'@ pipe:+-- | A self-contained pipeline that is ready to be run+type Pipeline = Pipe () Void ->>> runPipe $ printer <+< (take' 3 >> take' 4) <+< fromList [1..]-1-2-3-You shall not pass!-4-5-6-7-You shall not pass!+{- $create+    'yield' and 'await' are the only two primitives you need to create pipes.+    Since @Pipe a b m@ is a monad, you can assemble 'yield' and 'await'+    statements using ordinary @do@ notation.  Since @Pipe a b@ is also a monad+    transformer, you can use 'lift' to invoke the base monad.  For example, you+    could write a pipe stage that requests permission before forwarding any+    output: +> check :: (Show a) => Pipe a a IO r+> check = forever $ do+>     x <- await+>     lift $ putStrLn $ "Can '" ++ (show x) ++ "' pass?"+>     ok <- read <$> lift getLine+>     when ok (yield x) -} -{- $return-    Pipe composition imposes an important requirement: You can only compose-    pipes that have the same return type.  For example, I could write the-    following function:--> deliver :: (Monad m) => Int -> Consumer a m [a]-> deliver n = replicateM n await--    ... and I might try to compose it with @fromList@:-->>> runPipe $ deliver 3 <+< fromList [1..10] -- wrong!--    ... but this wouldn't type-check, because @fromList@ has a return type of-    @()@ and @deliver@ has a return type of @[Int]@.  Composition requires that-    every pipe has a return value ready in case it terminates first.--    Fortunately, we don't have to rewrite the @fromList@ function because we can-    just add a return value using vertical concatenation:-->>> runPipe $ deliver 3 <+< (fromList [1..10] >> return [])-[1,2,3]--    ... although a more idiomatic Haskell version would be:-->>> runPipe $ (Just <$> deliver 3) <+< (fromList [1..10] *> pure Nothing)-Just [1,2,3]--    This forces you to cover all code paths by thinking about what return value-    you would provide if something were to go wrong.  For example, let's say I-    were to make a mistake and request more input than @fromList@ can deliver:-->>> runPipe $ (Just <$> deliver 99) <+< (fromList [1..10] *> pure Nothing)-Nothing+{-|+    Wait for input from upstream. -    The type system saved me by forcing me to cover all corner cases and handle-    every way my program could terminate.+    'await' blocks until input is available from upstream. -}--{- $terminate--    Now what if you wanted to write a pipe that only reads from its input end-    (i.e. a 'Consumer') and returns a list of every value delivered to it when-    its input pipe terminates?--> toList :: (Monad m) => Consumer a m [a]-> toList = ???--    You can't write such a pipe because if its input terminates then it brings-    down @toList@ with it!  This is correct because @toList@ as defined is not-    compositional (yet!).--    To see why, let's say you somehow got @toList@ to work and the following-    imaginary code sample worked:-->>> runPipe $ toList <+< (fromList [1..5] >> return [])-[1,2,3,4,5]--    @toList@ is defined to return its value when the pipe immediately upstream-    (@fromList@ in this case) terminates.  This behavior immediately leads to a-    problem.  What if I were to insert an \"identity\" pipe between @toList@ and-    @fromList@:--> identity = forever $ await >>= yield-> -- This is how id is actually implemented!--    This pipe forwards every valued untouched, so we would expect it to not have-    any affect if we were to insert it in the middle:-->>> runPipe $ toList <+< identity <+< (fromList [1..5] >> return [])-??? -- Oops! Something other than [1,2,3,4,5], perhaps even non-termination--    The answer couldn't be @[1,2,3,4,5]@ because @toList@ would monitor -    @identity@ instead of @fromList@ and since @identity@ never terminates-    @toList@ never terminates.  This is what I mean when I say that @toList@'s-    specified behavior is non-compositional.  It only works if it is coupled-    directly to the desired pipe and breaks when you introduce intermediate-    stages.--    This was not an intentional design choice, but rather a direct consequence-    of enforcing the 'Category' laws when I was implementing 'Pipe''s 'Category'-    instance.  Satisfying the 'Category' laws forces code to be compositional.--    Note that a terminated pipe only brings down pipes composed with it.  To-    illustrate this, let's use the following example:--> p = do a <+< b->        c+await :: (Monad m) => Pipe a b m a+await = wrap $ Await return -    @a@, @b@, and @c@ are pipes, and @c@ shares the same input and output as-    the composite pipe @a <+< b@, otherwise we cannot combine them within the-    same monad.  In the above example, either @a@ or @b@ could terminate and-    bring down the other one since they are composed, but @c@ is guaranteed to-    continue after @a <+< b@ terminates because it is not composed with them.-    Conceptually, we can think of this as @c@ automatically taking over the-    pipe's channeling responsibilities when @a <+< b@ can no longer continue.-    There is no need to \"restart\" the input or output manually as in some-    other iteratee libraries.+{-|+    Deliver output downstream. -    The @pipes@ library, unlike other iteratee libraries, grounds its vertical-    and horizontal concatenation in category theory by deriving horizontal-    concatenation ('.') from its 'Category' instance and vertical concatenation-    ('>>') from its 'Monad' instance.  This makes it easier to reason about-    pipes because you can leverage your intuition about 'Category's and 'Monad's-    to understand their behavior.  The only 'Pipe'-specific primitives are-    'await' and 'yield'.+    'yield' restores control back upstream and binds the result to 'await'. -}--{- $resource-    Here's another problem with 'Pipe' composition: resource finalization.-    Let's say we have the file \"test.txt\" with the following contents:--> Line 1-> Line 2-> Line 3--  .. and we wish to lazily read one line at a time from it:--> readFile' :: Handle -> Producer Text IO ()-> readFile' h = do->     eof <- lift $ hIsEOF h->     when (not eof) $ do->         s <- lift $ hGetLine h->         yield s->         readFile' h--    We could then try to be slick and write a lazy version that only reads as-    many lines as we request:--> read' :: FilePath -> Producer Text IO ()-> read' = do->     lift $ putStrLn "Opening file ..."->     h <- lift $ openFile file ReadMode->     readFile' h->     lift $ putStrLn "Closing file ..."->     lift $ hClose h--    Now compose!-->>> runPipe $ printer <+< read' "test.xt"-Opening file ...-"Line 1"-"Line 2"-"Line 3"-Closing file ...--    So far, so good.  Equally important, the file is never opened if we replace-    @printer@ with a pipe that never demands input:-->>> runPipe $ (lift $ putStrLn "I don't need input") <+< read' "test.txt"-I don't need input--    There is still one problem, though. What if we wrote:+yield :: (Monad m) => b -> Pipe a b m ()+yield b = wrap $ Yield (b, return ()) ->>> runPipe $ printer <+< take' 2 <+< read' "test.txt"-Opening file ...-"Line 1"-"Line 2"-You shall not pass!+{-|+    Convert a pure function into a pipe -    Oh no!  While it was lazy and only read two lines from the file, it was also-    too lazy to properly close our file!  @take' 2@ terminated before @read'@,-    preventing @read'@ from properly closing \"test.txt\".  This is why 'Pipe'-    composition fails to guarantee deterministic finalization.+> pipe = forever $ do+>     x <- await+>     yield (f x) -}--{- $frame-    So how could we implement finalization, then?  The answer is to build a-    higher-order type on top of 'Pipe' and define a new composition that permits-    prompt, deterministic finalization.--    To do this, we import "Control.Pipe.Final", which exports the 'Frame' type,-    analogous to the 'Pipe' type, except more powerful.  To demonstrate it in-    action, let's rewrite our @take'@ function to be a 'Frame' instead.--> take' :: Int -> Frame a a IO ()-> take' n->   | n < 1 = Frame $ close $ lift $ putStrLn "You shall not pass!"->   | otherwise = Frame $ do->         replicateM_ (n - 1) $ do->             x <- awaitF->             yieldF x->         x <- awaitF->         close $ do->             lift $ putStrLn "You shall not pass!"->             yieldF x--    The type signature looks the same, except 'Pipe' has been replaced with-    'Frame'.  Also, now we have 'awaitF' instead of 'await' and 'yieldF' instead-    of 'yield'.  However, you'll notice two new things: 'close' and 'Frame'.--    'close' signals when we no longer need input from upstream.  If you try to-    request input other than @()@ after the 'close', you will get a type error.-    Whenever you 'close' a frame, composition finalizes every upstream frame and-    removes them from the pipeline.  The type error reflects the fact that if-    you 'awaitF' past that point there is no longer anything upstream to request-    input from.--    'Frame' is a newtype constructor that I use to give clearer type errors and-    abstract away the underlying implementation.  The reason is that if you were-    to expand out the full type that 'Frame' wraps you would get:--> Frame a b m r ~ Pipe (Maybe a) (m (), b) m (Pipe (Maybe ()) (m (), b) m r)-> -- Yuck!--    Really, the only reason the type is that complicated is because I avoid-    using language extensions to implement 'Frame's, otherwise it would look-    more like:--> Pipe (Maybe a) (m (), b) m r--    ... which isn't so bad.  In fact, it's not hard to understand what that-    type is doing.  The 'Maybe' is used to supply a 'Nothing' to 'await's when-    upstream terminates before 'yield'ing a value.  The @m ()@ is the most-    recent finalizer which is yielded alongside every value so that downstream-    pipes can finalize you if they terminate before requesting another value.-    The finalization machinery uses these tricks behind the scene to guarantee-    that your finalizers get called.  I provide a type synonym for this:+pipe :: (Monad m) => (a -> b) -> Pipe a b m r+pipe f = forever $ await >>= yield . f -> type Ensure a b m r = Pipe (Maybe a) (m (), b) m r+{- $category+    'Pipe's form a 'Category', meaning that you can compose 'Pipe's and also+    define an identity 'Pipe'. -    In other words, an 'Ensure'd pipe can intercept upstream termination and-    register finalizers for downstream to call in the event of premature-    termination.  A good way to think about the distinction between 'Ensure'-    and 'Frame' is that 'Ensure' is the 'Monad' and 'Frame' is the 'Category',-    unlike 'Pipe', which is both at the same time.+    'Pipe' composition binds the output of the upstream 'Pipe' to the input of+    the downstream 'Pipe'.  Like Haskell functions, 'Pipe's are lazy, meaning+    that upstream 'Pipe's are only evaluated as far as necessary to generate+    enough input for downstream 'Pipe's.  If any 'Pipe' terminates, it also+    terminates every 'Pipe' composed with it. -    Using this type synonym, we can rewrite the type that 'Frame' wraps:+    If you want to define a proper 'Category' instance you have to wrap the+    'Pipe' type using the newtype 'PipeC' in order to rearrange the type+    variables. -> Frame a b m r ~ Ensure a b m (Ensure () b m r)+    This means that if you want to compose pipes using ('.') from the 'Category'+    type class, you end up with a newtype mess: -    The first half of the type is the part of the pipe before you call 'close',-    the second half of the type is the part of the pipe after you call 'close'.-    Notice how the second half has a blocked input end.+> unPipeC (PipeC p1 . PipeC p2) -    However, I haven't yet shown you how to register finalizers.  That's easy,-    though, since you just use 'catchP' or 'finallyP', which are identical to-    their exception-handling counterparts, except they catch 'Frame'-    terminations in either direction.  Let's rewrite our @read'@ function using-    finalizers:+    You can avoid this by using convenient operators that do this newtype+    wrapping and unwrapping for you: -> readFile' :: Handle -> Ensure () Text IO ()-> readFile' h = do->     eof <- lift $ hIsEOF h->     when (not eof) $ do->         s <- lift $ hGetLine h->         yieldF s->         readFile' h+> p1 <+< p2 = unPipeC $ PipeC p1 . PipeC p2 >-> read' :: FilePath -> Frame () Text IO ()-> read' = Frame $ close $ do->     lift $ putStrLn "Opening file ..."->     h <- lift $ openFile file ReadMode->     finallyP (putStrLn "Closing file ..." >> hClose h)->              (readFile' h)--    Notice how @read'@ closes its input end immediately because it never-    requires input.  Also, the 'finallyP' ensures that the finalizer is called-    both if @read'@ terminates normally or is interrupted by another 'Frame'-    terminating first.--    Now, all we need to do is rewrite @printer@ to be a 'Frame':--> printer :: (Show b) => Frame b Void IO r-> printer = Frame $ forever $ do->     x <- awaitF->     lift $ print x--    This time we don't even need a 'close' statement because @printer@ never-    stops needing input.  Any non-terminating 'Frame' with a polymorphic return-    type can skip calling 'close' altogether, and it will type-check.--}--{- $framecompose--    Just like with 'Pipe's, we can compose 'Frame's, except now we use ('<-<'):--> stack :: Frame Void () IO ()-> stack = printer <-< take' 1 <-< read' "test.txt"+> idP = unPipeC id -    I call a complete set of 'Frame's a 'Stack', to reflect the fact that-    'Frame' composition uses the exact same tricks stack-based programming uses-    to guarantee deterministic finalization.  When a 'Frame' terminates it-    finalizes upstream 'Frame's as if they were a heap and it propagates an-    exceptional value ('Nothing' in this case) for downstream 'Frame's to-    intercept.  I provide a type synonym to reflect this:+    The 'Category' instance obeys the 'Category' laws.  In other words: -> type Stack m r = Frame Void () IO r+    * Composition is truly associative.  The result of composition produces the+      exact same composite 'Pipe' regardless of how you group composition, so it+      is perfectly safe to omit the parentheses altogether: -    So we can rewrite the type of @stack@ to be:+> (p1 <+< p2) <+< p3 = p1 <+< (p2 <+< p3) = p1 <+< p2 <+< p3 -> stack :: Stack IO ()+    * 'idP' is a true identity pipe.  Composing a pipe with 'idP' returns the+      exact same original pipe: -    To run a 'Stack', we use 'runFrame', which is the 'Frame'-based analog to-    'runPipe':+> p <+< idP = p+> idP <+< p = p ->>> runFrame stack-Opening file ...-"Line 1"-Closing file ...-"Line 2"-You shall not pass!+    The 'Category' laws are \"correct by construction\", meaning that you cannot+    break them despite the library's internals being fully exposed.  The above+    equalities are true using the strongest denotational semantics possible in+    Haskell, namely that both sides of the equals sign correspond to the exact+    same value in Haskell, constructor-for-constructor, value-for-value.  You+    cannot create a function that can distinguish the results. -    Not only did it correctly finalize the file this time, but it did so as-    promptly as possible!  I programmed @take'@ so that it knew it would not-    need @read'@ any longer before it 'yield'ed the second value, so it-    finalized the file before 'yield'ing the second value for @printer@.-    @take'@ did this without knowing anything about the 'Frame' upstream of it.-    One of the big advantages of 'Frame's is that you can reason about the-    finalization behavior of each 'Frame' in complete isolation from other-    'Frame's, allowing you to completely decouple their finalization-    behavior.+    Actually, all other class instances in this library provide the same strong+    guarantees for their corresponding laws.  I only emphasize the guarantee for+    the 'Category' instance because it is one of the most distinguishing+    features of this library, making it far more extensible than other+    implementations. -} -{- $frameensure-    Unfortunately, in the absence of extensions I have to split the 'Monad' and-    'Category' into two separate types.  'Ensure' is the 'Monad', 'Frame' is the-    'Category'.--    However, you can achieve the best of both worlds by programming all your-    pipes in the 'Ensure' monad, and then only adding 'close' at the last minute    when you are building your 'Stack'.  For example, if we wanted to read from-    multiple files, it would be much better to just remove the 'close' function-    from the @read'@ implementation, so it operates in the 'Ensure' monad:+-- | 'Pipe's form a 'Category' instance when you rearrange the type variables+newtype PipeC m r a b = PipeC { unPipeC :: Pipe a b m r} -> read' :: FilePath -> Ensure () Text IO ()+instance (Monad m) => Category (PipeC m r) where+    id = PipeC idP+    PipeC p1 . PipeC p2 = PipeC $ p1 <+< p2 -    Then use 'close' only after we've already concatenated our files:+-- | Corresponds to ('<<<')/('.') from @Control.Category@+(<+<) :: (Monad m) => Pipe b c m r -> Pipe a b m r -> Pipe a c m r+p1 <+< p2 = FreeT $ do+    x1 <- runFreeT p1+    let p1' = FreeT $ return x1+    runFreeT $ case x1 of+        Return r        -> return r+        Wrap (Yield y ) -> wrap $ Yield $ fmap (<+< p2) y+        Wrap (Await f1) -> FreeT $ do+            x2 <- runFreeT p2+            runFreeT $ case x2 of+                Return r            -> return r+                Wrap (Yield (x, p)) -> f1 x <+< p+                Wrap (Await f2    ) -> wrap $ Await $ fmap (p1' <+<) f2 -> files :: Frame () Text IO ()-> files = close $ do->     read' "test.txt"->     read' "dictionary.txt"->     read' "poem.txt"+-- | Corresponds to ('>>>') from @Control.Category@+(>+>) :: (Monad m) => Pipe a b m r -> Pipe b c m r -> Pipe a c m r+(>+>) = flip (<+<) -    This is a more idiomatic 'Frame' programming style that lets you take-    advantage of both the 'Monad' and 'Category' instances.+{- These associativities might help performance since pipe evaluation is+   downstream-biased.  I set them to the same priority as (.). -}+infixr 9 <+<+infixl 9 >+> -    The beauty of compositional finalization is we can decompose complicated-    problems into smaller ones.  Imagine that we have a resource that needs a-    fine-grained finalization behavior like in our @take'@ function which does-    a cute little optimization to finalize early.  We can always decompose our-    frame into one that does the straight-forward thing (like @read'@) and then-    just compose it with @take'@ to get the cute optimization for free.  In this-    way we've decomposed the problem into two separate problems: generating the-    resource and doing the cute optimization.--}+-- | Corresponds to 'id' from @Control.Category@+idP :: (Monad m) => Pipe a a m r+idP = pipe id -{- $fold-    'Frame's can actually do much more than manage finalization!  Using-    'Frame's, we can now correctly implement folds like @toList@ in a way that-    is truly compositional:+{- $runpipe+    Note that you can also unwrap a 'Pipe' a single step at a time using+    'runFreeT' (since 'Pipe' is just a type synonym for a free monad+    transformer).  This will take you to the next /external/ 'await' or 'yield'+    statement. -> toList :: (Monad m) => Frame a Void m [a]-> toList = Frame go where->     go = do->         x <- await->         case x of->             Nothing -> close $ pure []->             Just a  -> fmap (fmap (a:)) go->             -- the extra fmap is an unfortunate extra detail+    This means that a closed 'Pipeline' will unwrap to a single step, in which+    case you would have been better served by 'runPipe'.  This directly follows+    from the 'Category' laws, which guarantee that you cannot resolve a+    composite pipe into its component pipes.  When you compose two pipes, the+    internal await and yield statements fuse and completely disappear. -    This time I used an ordinary 'await', instead of 'awaitF', so I could access-    the underlying 'Maybe' values that these 'Frame's are passing around.-    Similarly, you could use 'yield' instead of 'yieldF' if you wanted to-    manually manage the finalizers passed downstream at each 'yield' statement-    instead of using the 'catchP' or 'finallyP' convenience functions.  Using-    these advanced features does not break any of the 'Category' laws.  I could-    expose every single internal of the library and you would not be able to-    break the 'Category' laws because the 'Frame's generated are still-    indistinguishable at the value level and fuse into the hand-written-    implementation.  The compositionality of 'Frame's is just as strong as the-    compositionality of 'Pipe's.+    'runFreeT' is ideal for more advanced users who wish to write their own+    'Pipe' functions while waiting for me to find more elegant solutions.+-}+{-|+    Run the 'Pipe' monad transformer, converting it back into the base monad. -    Now let's use our @toList@ function:+    'runPipe' imposes two conditions: ->>> runFrame $ (Just <$> toList) <-< (Nothing <$ fromList [1..3])-Just [1,2,3]+    * The pipe's input, if any, is trivially satisfiable (i.e. @()@) -    I still had to provide a return value for @fromList@ ('Nothing' in this-    case), because when @fromList@ terminates, it cannot guarantee that its-    return value will come from itself or from @toList@.  When @toList@ receives-    a 'Nothing' from upstream, it can choose to terminate and over-ride the-    return value from upstream or 'await' again and defer to the upstream return-    value (@fromList@ in this case).  It doesn't even have to immediately-    decide.  It could just 'yield' more values downstream and forget it had even-    received a 'Nothing' and if downstream terminates then composition will-    still ensure that everything \"just works\" the way you would expect and no-    finalizers are missed or duplicated.+    * The pipe does not 'yield' any output -    Composition handles every single corner case of finalization.  This directly-    follows from enforcing the 'Category' laws, because categories have no-    corners!--}+    The latter restriction makes 'runPipe' less polymorphic than it could be,+    and I settled on the restriction for three reasons: -{- $strict-    We can go a step further and modify @toList@ into something even cooler:+    * It prevents against accidental data loss. -> strict :: (Monad m) => Frame a a m ()-> strict = Frame $ do->     xs <- go->     close $ mapM_ yieldF xs->   where->     go = do->         x <- await->         case x of->             Nothing -> pure []->             Just a  -> fmap (a:) go+    * It prevents wastefully draining a scarce resource by gratuitously+      demanding values from it. -    As the name suggests, @strict@ is strict in its input.  We can use @strict@-    to load the entire resource into memory immediately, allowing us to finalize-    it early.  Let's use this to create a strict version of our file reader:+    * It encourages an idiomatic pipe programming style where input is consumed+      in a structured way using a 'Consumer'. ->>> runFrame $ printer <-< take' 2 <-< strict <-< read' "test.txt"-Opening file ...-Closing file ...-"Line 1"-"Line 2"-You shall not pass!+    If you believe that discarding output is the appropriate behavior, you can+    specify this by explicitly feeding your output to a pipe that gratuitously+    discards it: -    Now we have a way to seamlessly switch from laziness to strictness all-    implemented entirely within Haskell without the use of artificial 'seq'-    annotations.+> runPipe $ forever await <+< p -}--+runPipe :: (Monad m) => Pipeline m r -> m r+runPipe p = do+    e <- runFreeT p+    case e of+        Return r       -> return r+        Wrap (Await f) -> runPipe $ f ()+        Wrap (Yield y) -> runPipe $ snd y
− Control/Pipe/Common.hs
@@ -1,283 +0,0 @@-{-# LANGUAGE Rank2Types #-}--module Control.Pipe.Common (-    -- * Introduction-    -- $summary--    -- * Types-    -- $types-    PipeF(..),-    Pipe,-    Producer,-    Consumer,-    Pipeline,-    -- * Create Pipes-    -- $create-    await,-    yield,-    pipe,-    -- * Compose Pipes-    -- $newtype-    Lazy(..),-    -- $convenience-    (<+<),-    (>+>),-    idP,-    -- $category-    -- * Run Pipes-    -- $runpipe-    runPipe-    ) where--import Control.Applicative-import Control.Category-import Control.Monad (forever)-import Control.Monad.Trans.Class (lift)-import Control.Monad.Trans.Free-import Data.Void (Void)-import Prelude hiding ((.), id)--{- $summary-    I completely expose the 'Pipe' data type and internals in order to encourage-    people to write their own 'Pipe' functions.  This does not compromise the-    correctness or safety of the library at all and you can feel free to use the-    constructors directly without violating any laws or invariants.--    I promote using the 'Monad' and 'Category' instances to build and compose-    pipes, but this does not mean that they are the only option.  In fact, any-    combinator provided by other iteratee libraries can be recreated for pipes,-    too.  However, this core library does not provide many of the functions-    found in other libraries in order to encourage people to find principled and-    theoretically grounded solutions rather than devise ad-hoc solutions-    characteristic of other iteratee implementations.--}--{- $types-    The 'Pipe' type is strongly inspired by Mario Blazevic's @Coroutine@ type in-    his concurrency article from Issue 19 of The Monad Reader and is formulated-    in the exact same way.--    His @Coroutine@ type is actually a free monad transformer (i.e. 'FreeT')-    and his @InOrOut@ functor corresponds to 'PipeF'.--}-data PipeF a b x = Await (a -> x) | Yield (b, x)---- I could use the "DerivingFunctor" extension, but I want to remain portable-instance Functor (PipeF a b) where-    fmap f (Await a) = Await $ fmap f a-    fmap f (Yield y) = Yield $ fmap f y--{-|-    The base type for pipes--    * @a@ - The type of input received from upstream pipes--    * @b@ - The type of output delivered to downstream pipes--    * @m@ - The base monad--    * @r@ - The type of the return value--}-type Pipe a b = FreeT (PipeF a b)---- | A pipe that produces values-type Producer b = Pipe () b---- | A pipe that consumes values-type Consumer b = Pipe b Void---- | A self-contained pipeline that is ready to be run-type Pipeline = Pipe () Void--{- $create-    'yield' and 'await' are the only two primitives you need to create pipes.-    Since 'Pipe a b m' is a monad, you can assemble 'yield' and 'await'-    statements using ordinary @do@ notation.  Since 'Pipe a b' is also a monad-    transformer, you can use 'lift' to invoke the base monad.  For example, you-    could write a pipe stage that requests permission before forwarding any-    output:--> check :: (Show a) => Pipe a a IO r-> check = forever $ do->     x <- await->     lift $ putStrLn $ "Can '" ++ (show x) ++ "' pass?"->     ok <- read <$> lift getLine->     when ok (yield x)--}--{-|-    Wait for input from upstream.--    'await' blocks until input is available from upstream.--}-await :: (Monad m) => Pipe a b m a-await = wrap $ Await return--{-|-    Deliver output downstream.--    'yield' restores control back upstream and binds the result to 'await'.--}-yield :: (Monad m) => b -> Pipe a b m ()-yield b = wrap $ Yield (b, return ())--{-|-    Convert a pure function into a pipe--> pipe = forever $ do->     x <- await->     yield (f x)--}-pipe :: (Monad m) => (a -> b) -> Pipe a b m r-pipe f = forever $ await >>= yield . f--{- $newtype-    Pipes form a 'Category', but if you want to define a proper 'Category'-    instance you have to wrap the 'Pipe' type using a newtype in order to-    rearrange the type variables:--}-newtype Lazy m r a b = Lazy { unLazy :: Pipe a b m r}--instance (Monad m) => Category (Lazy m r) where-    id = Lazy idP-    Lazy p1 . Lazy p2 = Lazy $ p1 <+< p2--{- $convenience-    This means that if you want to compose pipes using ('.') from the 'Category'-    type class, you end up with a newtype mess: @unLazy (Lazy p1 . Lazy p2)@.--    You can avoid this by using convenient operators that do this newtype-    wrapping and unwrapping for you:--> p1 <+< p2 = unLazy $ Lazy p1 . Lazy p2->-> idP = unLazy id--}---- | Corresponds to ('<<<')/('.') from @Control.Category@-(<+<) :: (Monad m) => Pipe b c m r -> Pipe a b m r -> Pipe a c m r-p1 <+< p2 = FreeT $ do-    x1 <- runFreeT p1-    let p1' = FreeT $ return x1-    runFreeT $ case x1 of-        Pure r         -> pure r-        Wrap (Yield y) -> wrap $ Yield $ fmap (<+< p2) y-        Wrap (Await f1) -> FreeT $ do-            x2 <- runFreeT p2-            runFreeT $ case x2 of-                Pure r              -> pure r-                Wrap (Yield (x, p)) -> f1 x <+< p-                Wrap (Await f2    ) -> wrap $ Await $ fmap (p1' <+<) f2---- | Corresponds to ('>>>') from @Control.Category@-(>+>) :: (Monad m) => Pipe a b m r -> Pipe b c m r -> Pipe a c m r-(>+>) = flip (<+<)--{- These associativities might help performance since pipe evaluation is-   downstream-biased.  I set them to the same priority as (.). -}-infixr 9 <+<-infixl 9 >+>---- | Corresponds to 'id' from @Control.Category@-idP :: (Monad m) => Pipe a a m r-idP = pipe id--{- $category-    You can compose two pipes using @p1 <+< p2@, which binds the output of @p2@-    to the input of @p1@.  For example:--> (await >>= lift . print) <+< yield 0-> = lift (print 0)--    'idP' is the identity pipe which forwards all output untouched:--> idP = forever $ do->   x <- await->   yield x--    Pipes are lazy, meaning that control begins at the downstream pipe and-    control only transfers upstream when the downstream pipe 'await's input from-    upstream.  If a pipe never 'await's input, then pipes upstream of it will-    never run.--    Upstream pipes relinquish control back downstream whenever they 'yield' an-    output value.  This binds the 'yield'ed value to the return value of the-    downstream 'await'.  The upstream pipe does not regain control unless the-    downstream pipe requests input again.--    When a pipe terminates, it also terminates any pipes composed with it.--    The 'Category' instance obeys the 'Category' laws.  In other words:--    * Composition is truly associative.  The result of composition produces the-      exact same composite 'Pipe' regardless of how you group composition:--> (p1 <+< p2) <+< p3 = p1 <+< (p2 <+< p3)--    * 'idP' is a true identity pipe.  Composing a pipe with 'idP' returns the-      exact same original pipe:--> p <+< idP = p-> idP <+< p = p--    The 'Category' laws are \"correct by construction\", meaning that you cannot-    break them despite the library's internals being fully exposed.  The above-    equalities are true using the strongest denotational semantics possible in-    Haskell, namely that both sides of the equals sign correspond to the exact-    same value in Haskell, constructor-for-constructor, value-for-value.  You-    cannot create a function that can distinguish the results.--    Actually, all other class instances for 'Pipe's provide the same strong-    guarantees for their corresponding laws.  I only emphasize the guarantee for-    the 'Category' instance because it is one of the most distinguishing-    features of this library.--}--{- $runpipe-    Note that you can also unwrap a 'Pipe' a single step at a time using-    'runFreeT' (since 'Pipe' is just a type synonym for a free monad-    transformer).  This will take you to the next /external/ 'await' or 'yield'-    statement.--    This means that a closed 'Pipeline' will unwrap to a single step, in which-    case you would have been better served by 'runPipe'.  This directly follows-    from the 'Category' laws, which guarantee that you cannot resolve a-    composite pipe into its component pipes.  When you compose two pipes, the-    internal await and yield statements fuse and completely disappear.--    'runFreeT' is ideal for more advanced users who wish to write their own-    'Pipe' functions while waiting for me to find more elegant solutions.--}-{-|-    Run the 'Pipe' monad transformer, converting it back into the base monad.--    'runPipe' imposes two conditions:--    * The pipe's input, if any, is trivially satisfiable (i.e. @()@)--    * The pipe does not 'yield' any output--    The latter restriction makes 'runPipe' less polymorphic than it could be,-    and I settled on the restriction for three reasons:--    * It prevents against accidental data loss.--    * It prevents wastefully draining a scarce resource by gratuitously-      demanding values from it.--    * It encourages an idiomatic pipe programming style where input is consumed-      in a structured way using a 'Consumer'.--    If you believe that discarding output is the appropriate behavior, you can-    specify this by explicitly feeding your output to a pipe that gratuitously-    discards it:--> runPipe $ forever await <+< p--}-runPipe :: (Monad m) => Pipeline m r -> m r-runPipe p = do-    e <- runFreeT p-    case e of-        Pure   r       -> return r-        Wrap (Await f) -> runPipe $ f ()-        Wrap (Yield y) -> runPipe $ snd y
− Control/Pipe/Final.hs
@@ -1,424 +0,0 @@-module Control.Pipe.Final (-    -- * Introduction-    -- $intro--    -- * Types-    Prompt,-    Ensure,-    Frame(..),-    Stack,-    -- * Create Frames-    -- $create-    yieldF,-    awaitF,-    -- * Prompt Finalization-    -- $prompt-    close,-    bindClosed,-    reopen,-    -- * Ensure Finalization-    -- $ensure-    catchP,-    finallyP,-    -- * Compose Frames-    -- $compose-    (<-<),-    (>->),-    idF,-    FrameC(..),-    -- * Run Frames-    -- $run-    runFrame-    ) where--import Control.Applicative-import Control.Category-import Control.Monad-import Control.Monad.Trans.Class-import Control.Monad.Trans.Free-import Control.Pipe.Common-import Data.Void-import Prelude hiding ((.), id)--{- $intro-    A 'Frame' is a higher-order type built on top of 'Pipe'.  It enables a-    richer composition with the ability to finalize resources in a manner that-    is:--    * Prompt: You can close resources when you no longer need input from them--    * Deterministic: Composition finalizes every 'Frame' when one terminates--    'Frame's differ from 'Pipe's in that they do not form monads, but instead-    form parametrized monads.  Unfortunately, parametrized monads are not-    mainstream in Haskell and require a ton of extensions along with a modified-    Prelude in order to recover @do@ notation, so this first release of the-    'Frame' implementation essentially \"in-lines\" the parametrized monad by-    splitting it into two monads.  Future releases will split off a version that-    takes advantage of parametrized monads for a much simpler underlying type-    and a significantly cleaner implementation.--    Ordinary users should start at the section \"Create Frames\", but if you-    encounter weird type errors and want to understand them, then consult the-    \"Types\" section.--}--{-|-    An illustrative type synonym that demonstrates how 'Prompt' finalization-    works--    This type simulates a parametrized monad by breaking it up into two monads-    where the first monad returns the second one.  The first monad permits any-    pipe code and the second monad only permits pipe code that doesn't need-    input.--    For example if @p = Pipe@, the first monad becomes an ordinary 'Pipe' and-    the second monad becomes a 'Producer':--> Prompt Pipe a b m r = Pipe a b m (Pipe () b m r)--    The pipe does not require input by the time it reaches the second block,-    meaning that the finalization machinery can safely finalize upstream-    resources the moment.  The earlier you use 'close' the input end,-    the more promptly you release upstream resources.--    The finalization machinery also finalizes downstream pipes when the-    second monad terminates.  I use this trick to ensure a strict ordering of-    finalizers from upstream to downstream.--    I don't actually use the 'Prompt' type synonym, since that would require-    newtyping everything, but I will reference it in documentation to clarify-    type signatures.--}-type Prompt p a b m r = p a b m (p () b m r)--{-|-    A pipe type that 'Ensure's deterministic finalization--    The finalization machinery uses the input and output ends in different ways-    to finalize the pipe when another pipe terminates first.--    If an upstream pipe terminates first, the current pipe will receive a-    'Nothing' once.  This allows it to finalize itself and if it terminates then-    its return value takes precedence over upstream's return value.  However, if-    it 'await's again, it defers to upstream's return value and never regains-    control.  You do not need to \"rethrow\" the 'Nothing' (nor can you):-    composition takes care of this for you.--    On the output end, the pipe must supply its most up-to-date finalizer-    alongside every value it 'yield's downstream.  This finalizer is guaranteed-    to be called if downstream terminates first.  You do not need to relay-    upstream finalizers alongside the pipe's own finalizer (nor can you):-    composition takes care of this for you.--    The combination of these two tricks allows a bidirectional guarantee of-    deterministic finalization that satisfies the 'Category' laws.--}-type Ensure a b m r = Pipe (Maybe a) (m (), b) m r--{-|-    A pipe type that combines 'Prompt' and 'Ensure' to enable both prompt and-    deterministic finalization.--    The name connotes a stack frame, since finalized pipes can be thought of as-    forming the 'Category' of stack frames, where upstream finalization is-    equivalent to finalizing the heap, and downstream finalization is equivalent-    to throwing an exception up the stack.--    The type is equivalent to:--> type Frame a b m r = Prompt Ensure a b m r--}-newtype Frame a b m r = Frame { unFrame :: Ensure a b m (Ensure () b  m r) }--instance (Monad m) => Functor (Frame a b m) where-    fmap f (Frame p) = Frame $ fmap (fmap f) p---- | A 'Stack' is a 'Frame' that doesn't need input and doesn't generate output-type Stack = Frame () Void--{- $create-    The first step to convert 'Pipe' code to 'Frame' code is to replace all-    'yield's with 'yieldF's and all 'await's with 'awaitF's.--> contrived = do   -->  contrived = do->     x1 <- await  -->      x1 <- awaitF->     yield x1     -->      yieldF x1->     x2 <- await  -->      x2 <- awaitF->     yield x2     -->      yieldF x2--}---- | Like 'yield', but also yields an empty finalizer alongside the value-yieldF :: (Monad m) => b -> Ensure a b m ()-yieldF x = yield (unit, x)---- | Like 'await', but ignores all 'Nothing's and just awaits again-awaitF :: (Monad m) => Ensure a b m a-awaitF = await >>= maybe awaitF return--{- $prompt-    The second step to convert 'Pipe' code to 'Frame' code is to mark the point-    where your 'Pipe' no longer 'await's by wrapping it in the 'close' function-    and then wrapping the 'Pipe' in a 'Frame' newtype:--> contrived :: (Monad m) => Frame a a m ()-> contrived = Frame $ do->     x1 <- awaitF->     yieldF x1->     x2 <- awaitF->     close $ yieldF x2--    If a non-terminating pipe demands input indefinitely, there is no need to-    'close' it.  It will type-check if the return value is polymorphic as a -    result of non-termination.--}--{-|-    Use this to mark when a 'Frame' no longer requires input.  The earlier the-    better!--}-close :: (Monad m) => Ensure () b m r -> Ensure a b m (Ensure () b m r)-close = pure--{-|-    Use this to bind to the 'close'd half of the 'Frame' if you want to continue-    where it left off but you still don't require input.--    This function would not be necessary if 'Prompt' were implemented as a-    parametrized monad, so if it seems ugly, that's because it is.--}-bindClosed :: (Monad m) =>-    Frame a b m r1 -> (r1 -> Ensure () b m r2) -> Frame a b m r2-bindClosed (Frame p) f = Frame $ fmap (>>= f) p--{-|-    Use this to 'reopen' a 'Frame' if you change your mind and decide you want-    to continue to 'await' input after all.--    This postpones finalization of upstream until you 'close' the input end-    again.--}-reopen :: (Monad m) => Frame a b m r -> Ensure a b m r-reopen (Frame p) = join $ fmap (<+< (forever $ yield $ Just ())) p--{- $ensure-    The third (optional) step to convert 'Pipe' code to 'Frame' code is to use-    'catchP' or 'finallyP' to register finalizers for blocks of code.--> contrived :: Frame a a IO ()-> contrived = Frame $ do->     catchP (putStrLn "Stage 1 interrupted") $ do->         x1 <- awaitF->         catchP (putStrLn "Stage 1(b) interrupted") $ yieldF x1->     catchP (putStrLn "Stage 2 interrupted") $ do->         x2 <- awaitF->         close $ yieldF x2--}--{-|-    @catchP m p@ registers @m@ to be called only if another composed-    pipe terminates before @p@ is done.--}-catchP :: (Monad m) => m () -> Ensure a b m r -> Ensure a b m r-catchP m p = FreeT $ do-    x <- runFreeT p-    runFreeT $ case x of-        Pure r -> pure r-        Wrap (Yield ((m', b), p')) -> wrap $ Yield ((m' >> m, b), catchP m p')-        Wrap (Await f) -> wrap $ Await $ \e -> case e of-            Nothing -> lift m >> catchP m (f e)-            Just _  ->           catchP m (f e)-{- catchP is equivalent to:--awaitF' m = await >>= maybe (lift m >> awaitF' m) return--yieldF' m x = yield (m, x)--catchP m p =  reopen $-     (forever $ awaitF >>= yieldF' m)- <-< Frame (fmap close p)- <-< (forever $ awaitF' m >>= yieldF) -}--{-|-    'finallyP' is like 'catchP' except that it also calls the finalizer if @p@-    completes normally.--}-finallyP :: (Monad m) => m () -> Ensure a b m r -> Ensure a b m r-finallyP m p = do-    r <- catchP m p-    lift m-    return r--(<~<) :: (Monad m)- => Pipe b c m (Pipe x c m r)- -> Pipe a b m (Pipe x b m r)- -> Pipe a c m (Pipe x c m r)-p1 <~< p2 = FreeT $ do-    x1 <- runFreeT p1-    runFreeT $ case x1 of-        Pure p1'       -> pure p1'-        Wrap (Yield y) -> wrap $ Yield $ fmap (<~< p2) y-        Wrap (Await f1) -> FreeT $ do-            let p1 = FreeT $ return x1-            x2 <- runFreeT p2-            runFreeT $ case x2 of-                Pure p2'              -> pure $ p1 <~| p2'-                Wrap (Yield (b2, p2')) -> f1 b2 <~< p2'-                Wrap (Await f2      ) -> wrap $ Await $ fmap (p1 <~<) f2--(<~|) :: (Monad m)- => Pipe b c m (Pipe x c m r)- -> Pipe x b m r- -> Pipe x c m r-p1 <~| p2 = FreeT $ do-    x1 <- runFreeT p1-    runFreeT $ case x1 of-        Pure p1'        -> p1'-        Wrap (Yield y) -> wrap $ Yield $ fmap (<~| p2) y-        Wrap (Await f) -> FreeT $ do-            let p1 = FreeT $ return x1-            x2 <- runFreeT p2-            runFreeT $ case x2 of-                Pure r                -> pure r-                Wrap (Yield (b2, p2')) -> f b2 <~| p2'-                Wrap (Await f2      ) -> wrap $ Await $ fmap (p1 <~|) f2--unit :: (Monad m) => m ()-unit = return ()--mult :: (Monad m)- => m ()- -> Pipe (Maybe        b ) (m (), c) m (Pipe x (m (), c) m r)- -> Pipe (Maybe (m (), b)) (m (), c) m (Pipe x (m (), c) m r)-mult m p = FreeT $ do-    x <- runFreeT p-    runFreeT $ case x of-        Pure p' -> pure $ lift m >> p'-        Wrap (Yield ((m', c), p')) -> wrap $ Yield ((m >> m', c), mult m p')-        Wrap (Await f) -> wrap $ Await $ \e -> case e of-            Nothing      -> mult unit (f   Nothing)-            Just (m', b) -> mult m'   (f $ Just b )--comult :: (Monad m)- => Pipe (Maybe a)        b  m (Pipe x        b  m r)- -> Pipe (Maybe a) (Maybe b) m (Pipe x (Maybe b) m r)-comult p = FreeT $ do-    x <- runFreeT p-    runFreeT $ case x of-        Pure p' -> pure $ warn p'-        Wrap (Yield (b, p')) -> wrap $ Yield (Just b, comult p')-        Wrap (Await f) -> wrap $ Await $ \e -> case e of-            Nothing -> schedule $ comult (f e)-            Just _  ->            comult (f e)--warn :: (Monad m)- => Pipe x        b  m r- -> Pipe x (Maybe b) m r-warn p = do-    r <- pipe Just <+< p-    yield Nothing-    return r--schedule :: (Monad m)- => Pipe (Maybe a) (Maybe b) m (Pipe x (Maybe b) m r)- -> Pipe (Maybe a) (Maybe b) m (Pipe x (Maybe b) m r)-schedule p = FreeT $ do-    x <- runFreeT p-    runFreeT $ case x of-        Pure p' -> pure p'-        Wrap (Await f) -> wrap $ Yield (Nothing, wrap $ Await f)-        Wrap (Yield y) -> wrap $ Yield $ fmap schedule y--{- $compose-    The fourth step to convert 'Pipe' code to 'Frame' code is to use ('<-<') to-    compose 'Frame's instead of ('<+<').--> printer  :: Frame a Void IO r-> fromList :: (Monad m) => [a] -> Frame () a m ()->-> p :: Stack IO ()-> p = printer <-< contrived <-< fromList [1..]--    Similarly, 'idF' replaces 'idP'.--    When a 'Frame' terminates, the 'FrameC' category strictly orders the-    finalizers from upstream to downstream.  Specifically:--    * When any 'Frame' 'close's its input end, it finalizes all 'Frame's-      upstream of it.  These finalizers are ordered from upstream to downstream.--    * A 'Frame' is responsible for finalizing its own resources under ordinary-      operation (either manually, or using 'finallyP').--    * When a 'Frame' terminates, everything downstream of it is finalized.-      These finalizers are ordered from upstream to downstream.--    The 'Category' instance for 'FrameC' provides the same strong guarantees as-    the 'Lazy' category.  This confers many practical advantages:--    * Finalizers are never duplicated or dropped in corner cases.--    * The grouping of composition will never affect the ordering or behavior of-      finalizers.--    * Finalization does not grow more complex the more 'Frame's you add in your-      'Stack'.--    * You can reason about the finalization behavior of each 'Frame'-      independently of other 'Frame's it is composed with.--}---- | Corresponds to 'id' from @Control.Category@-idF :: (Monad m) => Frame a a m r-idF = Frame $ forever $ awaitF >>= yieldF---- | Corresponds to ('<<<')/('.') from @Control.Category@-(<-<) :: (Monad m) => Frame b c m r -> Frame a b m r -> Frame a c m r-(Frame p1) <-< (Frame p2) = Frame $ mult unit p1 <~< comult p2---- | Corresponds to ('>>>') from @Control.Category@-(>->) :: (Monad m) => Frame a b m r -> Frame b c m r -> Frame a c m r-(>->) = flip (<-<)--newtype FrameC m r a b = FrameC { unFrameC :: Frame a b m r }--instance (Monad m) => Category (FrameC m r) where-    (FrameC p1) . (FrameC p2) = FrameC $ p1 <-< p2-    id = FrameC idF--{- $run-    The final step to convert 'Pipe' code to 'Frame' code is to replace-    'runPipe' with 'runFrame'.--> printer  :: Frame a Void IO r-> take     :: (Monad m) => Int -> Frame a a m ()-> fromList :: (Monad m) => [a] -> Frame () a m ()-->>> runFrame $ printer <-< contrived <-< fromList [1..]-1-2-->>> runFrame $ printer <-< contrived <-< fromList [1]-1-Stage 2 interrupted-->>> runFrame $ printer <-< take 1 <-< contrived <-< fromList [1..]-Stage 1(b) interrupted-Stage 1 interrupted-1--For the last example, remember that 'take' is written to 'close' its input end-before yielding its final value, which is why the finalizers run before-@printer@ receives the 1.---}---- | Convert a 'Frame' back to the base monad.-runFrame :: (Monad m) => Stack m r -> m r-runFrame p = go (reopen p) where-    go p = do-        x <- runFreeT p-        case x of-            Pure r -> return r-            Wrap (Await f) -> go $ f (Just ())-            Wrap (Yield y) -> go $ snd y
+ Control/Pipe/Tutorial.hs view
@@ -0,0 +1,503 @@+{-|+    This module provides the tutorial for "Control.Pipe".+-}++module Control.Pipe.Tutorial (+    -- * Types+    -- $type++    -- * Composition+    -- $compose++    -- * Modularity+    -- $modular++    -- * Vertical Concatenation+    -- $vertical++    -- * Return Values+    -- $return++    -- * Termination+    -- $terminate++    -- * Resource Management+    -- $resource++    -- *Frames+    -- $frames+    ) where++-- For documentation+import Control.Category+import Control.Frame hiding (await, yield)+import Control.Monad.Trans.Class+import Control.Pipe+import Data.Void++{- $type+    This library represents streaming computations using a single data type:+    'Pipe'.++    'Pipe' is a monad transformer that extends the base monad with the ability+    to 'await' input from or 'yield' output to other 'Pipe's.  'Pipe's resemble+    enumeratees in other libraries because they receive an input stream and+    transform it into a new output stream.++    I'll introduce our first 'Pipe', which is a verbose version of the Prelude's+    'take' function:++> take' :: Int -> Pipe a a IO ()+> take' n = do+>     replicateM_ n $ do+>         x <- await+>         yield x+>     lift $ putStrLn "You shall not pass!"++    This 'Pipe' forwards the first @n@ values it receives undisturbed, then it+    outputs a cute message.++    Let's dissect the above 'Pipe''s type to learn a bit about how 'Pipe's work:++>      | Input Type | Output Type | Base monad | Return value+> Pipe   a            a             IO           ()++    So @take'@ 'await's input values of type \'@a@\' from upstream 'Pipe's and+    'yield's output values of type \'@a@\' to downstream 'Pipe's.  @take'@ uses+    'IO' as its base monad because it invokes the 'putStrLn' function.  If we+    were to remove the call to 'putStrLn', the compiler would infer the+    following type instead, which is polymorphic in the base monad:++> take' :: (Monad m) => Int -> Pipe a a m ()++    Now let's create a function that converts a list into a 'Pipe' by 'yield'ing+    each element of the list:++> fromList :: (Monad m) => [b] -> Pipe a b m ()+> fromList = mapM_ yield++    Note that @fromList xs@ is polymorphic in its input.  This is because it+    does not 'await' any input.  If we wanted, we could type-restrict it to:++> fromList :: (Monad m) => [b] -> Pipe () b m ()++    There is no type that forbids a 'Pipe' from 'await'ing, but you can+    guarantee that if it does 'await', the request is trivially satisfiable by+    supplying it with @()@.++    A 'Pipe' that doesn't 'await' (any useful input) can serve as the first+    stage in a 'Pipeline'.  I provide a type synonym for this common case:++> type Producer b m r = Pipe () b m r++    'Producer's resemble enumerators in other libraries because they function as+    data sources.++    You can then use the 'Producer' type synonym to rewrite the type signature+    for @fromList@ as:++> fromList :: (Monad m) => [b] -> Producer b m ()++    Now let's create a 'Pipe' that prints every value delivered to it:++> printer :: (Show b) => Pipe b c IO r+> printer = forever $ do+>     x <- await+>     lift $ print x++    Here, @printer@ is polymorphic in its output.  We could type-restrict it to+    guarantee it will never 'yield' by setting the output to 'Void', from+    @Data.Void@:++> printer :: (Show b) => Pipe b Void IO r++    A 'Pipe' that never 'yield's can be the final stage in a 'Pipeline'.  Again,+    I provide a type synonym for this common case:++> type Consumer b m r = Pipe b Void m r++    So we could instead write @printer@'s type as:++> printer :: (Show b) => Consumer b IO r++    'Consumer's resemble iteratees in other libraries because they function as+    data sinks.+-}++{- $compose+    What distinguishes 'Pipe's from every other iteratee implementation is that+    they form a true 'Category'.  Because of this, you can literally compose+    'Pipe's into 'Pipeline's using ordinary composition:++> newtype PipeC m r a b = PipeC { unPipeC :: Pipe a b m r }+> instance Category (PipeC m r) where ...++    For example, you can compose the above 'Pipe's with:++> pipeline :: Pipe () Void IO ()+> pipeline = unPipeC $ PipeC printer . PipeC (take' 3) . PipeC (fromList [1..])++    The compiler deduces that the final 'Pipe' must be blocked at both ends,+    meaning it will never 'await' useful input and it will never 'yield' any+    output.  This represents a self-contained 'Pipeline' and I provide a type+    synonym for this common case:++> type Pipeline m r = Pipe () Void m r++    Also, I provide '<+<' as a convenience operator for composing 'Pipe's+    without the burden of wrapping and unwrapping newtypes:++> p1 <+< p2 == unPipeC $ PipeC p1 . PipeC p2++    So you can rewrite @pipeline@ as:++> pipeline :: Pipeline IO ()+> pipeline = printer <+< take' 3 <+< fromList [1..]++    Like many other monad transformers, you convert the 'Pipe' monad back to the+    base monad using some sort of \"@run...@\" function.  In this case, it's the+    'runPipe' function:++> runPipe :: (Monad m) => Pipeline m r -> m r++    'runPipe' only works on self-contained 'Pipeline's, but you don't need to+    worry about explicitly type-restricting any of your 'Pipe's.  Self-contained+    'Pipeline's will automatically have polymorphic input and output ends and+    they will type-check when you provide them to 'runPipe'.++    Let's try using 'runPipe':++>>> runPipe pipeline+1+2+3+You shall not pass!++    Fascinating!  Our 'Pipe' terminates even though @printer@ never terminates+    and @fromList@ never terminates when given an infinite list.  To illustrate+    why our 'Pipe' terminates, let's outline the 'Pipe' flow control rules for+    composition:++    * 'Pipe's are lazy, so execution begins at the most downstream 'Pipe'+      (@printer@ in our example).++    * Upstream 'Pipe's only run if input is requested from them and they only+      run as long as necessary to 'yield' back a value.++    * If a 'Pipe' terminates, it terminates every other 'Pipe' composed with it.++    Another way to think of this is like a stack where each 'Pipe' is a frame on+    that stack:++    * If a 'Pipe' 'await's input, it blocks and pushes the next 'Pipe' upstream+      onto the stack until that 'Pipe' 'yield's back a value.++    * If a 'Pipe' 'yield's output, it pops itself off the stack and restores+      control to the original downstream 'Pipe' that was 'await'ing its input.+      This binds its result to the return value of the pending 'await' command.++    All of these flow control rules uniquely follow from the 'Category' laws.++    It might surprise you that termination brings down the entire 'Pipeline'+    until you realize that:++    * Downstream 'Pipe's depending on the terminated 'Pipe' cannot proceed++    * Upstream 'Pipe's won't be further evaluated because the terminated 'Pipe'+      will not request any further input from them++    So in our previous example, the 'Pipeline' terminated because \"@take' 3@\"+    terminated and brought down the entire 'Pipeline' with it.++    Actually, these flow control rules will mislead you into thinking that+    composed 'Pipe's behave as a collection of sub-'Pipe's with some sort of+    message passing architecture between them, but nothing could be further from+    the truth! When you compose 'Pipe's, they automatically fuse into a single+    'Pipe' that corresponds to how you would have written the control flow by+    hand.++    For example, if you compose @printer@ and @fromList@:++> printer <+< fromList [1..]++    The result is indistinguishable from:++> lift (mapM_ print [1..])++    ... which is what we would have written by hand if we had not used 'Pipe's+    at all!  All 'runPipe' does is just remove the 'lift'!+-}++{- $modular+    Given a loop like:++> loop :: IO r+> loop = forever $ do+>     x <- dataSource+>     y <- processData x+>     dataSink y++    We could decompose it into three separate parts:++> stage1 :: Producer a IO r+> stage1 = forever $ do+>     x <- dataSource+>     yield x+>+> stage2 :: Pipe a b IO r+> stage2 = forever $ do+>     x <- await+>     y <- processData x+>     yield y+>+>+> stage3 :: Consumer b IO r+> stage3 = forever $ do+>     y <- await+>     dataSink y+>+> stage3 <+< stage2 <+< stage1 = lift loop++    In other words, 'Pipe's let you decompose loops into modular components,+    which promotes loose coupling and allows you to freely mix and match those+    components.++    To demonstrate this, let's define a new data source that indefinitely+    prompts the user for integers:++> prompt :: Producer Int IO a+> prompt = forever $ do+>     lift $ putStrLn "Enter a number: "+>     n <- read <$> lift getLine+>     yield n++    Now we can use it as a drop-in replacement for @fromList@:++>>> runPipe $ printer <+< take' 3 <+< prompt+Enter a number:+1<Enter>+1+Enter a number:+2<Enter>+2+Enter a number:+3<Enter>+3+You shall not pass!++-}++{- $vertical+    You can easily \"vertically\" concatenate 'Pipe's, 'Producer's, and+    'Consumer's, all using simple monad sequencing: ('>>').  For example, here+    is how you concatenate 'Producer's:++>>> runPipe $ printer <+< (fromList [1..3] >> fromList [10..12])+1+2+3+10+11+12++    Here's how you would concatenate 'Consumer's:++>>> let print' n = printer <+< take' n :: (Show a) => Int -> Consumer a IO ()+>>> runPipe $ (print' 3 >> print' 4) <+< fromList [1..]+1+2+3+You shall not pass!+4+5+6+7+You shall not pass!++   ... but the above example is gratuitous because we could have just+   concatenated the intermediate @take'@ 'Pipe':++>>> runPipe $ printer <+< (take' 3 >> take' 4) <+< fromList [1..]+1+2+3+You shall not pass!+4+5+6+7+You shall not pass!++-}++{- $return+    'Pipe' composition imposes an important requirement: You can only compose+    'Pipe's that have the same return type.  For example, I could write the+    following function:++> deliver :: (Monad m) => Int -> Consumer a m [a]+> deliver n = replicateM n await++    ... and I might try to compose it with @fromList@:++>>> runPipe $ deliver 3 <+< fromList [1..10] -- wrong!++    ... but this wouldn't type-check, because @fromList@ has a return type of+    @()@ and @deliver@ has a return type of @[Int]@.  Composition requires that+    every 'Pipe' has a return value ready in case it terminates first.++    Fortunately, we don't have to rewrite the @fromList@ function because we can+    just add a return value using vertical concatenation:++>>> runPipe $ deliver 3 <+< (fromList [1..10] >> return [])+[1,2,3]++    ... although a more idiomatic Haskell version would be:++>>> runPipe $ (Just <$> deliver 3) <+< (fromList [1..10] *> pure Nothing)+Just [1,2,3]++    This forces you to cover all code paths by thinking about what return value+    you would provide if something were to go wrong.  For example, let's say I+    were to make a mistake and request more input than @fromList@ can deliver:++>>> runPipe $ (Just <$> deliver 99) <+< (fromList [1..10] *> pure Nothing)+Nothing++    The type system saved me by forcing me to cover all corner cases and handle+    every way my program could terminate.+-}++{- $terminate++    Now what if you wanted to write a 'Pipe' that only reads from its input end+    (i.e. a 'Consumer') and returns a list of every value delivered to it when+    its input 'Pipe' terminates?++> toList :: (Monad m) => Consumer a m [a]+> toList = ???++    You can't write such a 'Pipe' because if its input terminates then it brings+    down @toList@ with it!  This is correct because @toList@ as defined is not+    compositional (yet!).++    To see why, let's say you somehow got @toList@ to work and the following+    imaginary code sample worked:++>>> runPipe $ toList <+< (fromList [1..5] >> return [])+[1,2,3,4,5]++    @toList@ is defined to return its value when the 'Pipe' immediately upstream+    (@fromList@ in this case) terminates.  This behavior immediately leads to a+    problem.  What if I were to insert an \"identity\" 'Pipe' between @toList@+    and @fromList@:++> identity = forever $ await >>= yield+> -- This is how id is actually implemented!++    This 'Pipe' forwards every valued untouched, so we would expect it to not+    have any affect if we were to insert it in the middle:++>>> runPipe $ toList <+< identity <+< (fromList [1..5] >> return [])+??? -- Oops! Something other than [1,2,3,4,5], perhaps even non-termination++    The answer couldn't be @[1,2,3,4,5]@ because @toList@ would monitor +    @identity@ instead of @fromList@ and since @identity@ never terminates+    @toList@ never terminates.  This is what I mean when I say that @toList@'s+    specified behavior is non-compositional.  It only works if it is coupled+    directly to the desired 'Pipe' and breaks when you introduce intermediate+    stages.++    This was not an intentional design choice, but rather a direct consequence+    of enforcing the 'Category' laws when I was implementing 'Pipe''s 'Category'+    instance.  Satisfying the 'Category' laws forces code to be compositional.++    Note that a terminated 'Pipe' only brings down 'Pipe's composed with it.  To+    illustrate this, let's use the following example:++> p = do a <+< b+>        c++    @a@, @b@, and @c@ are 'Pipe's, and @c@ shares the same input and output as+    the composite 'Pipe' @a <+< b@, otherwise we cannot combine them within the+    same monad.  In the above example, either @a@ or @b@ could terminate and+    bring down the other one since they are composed, but @c@ is guaranteed to+    continue after @a <+< b@ terminates because it is not composed with them.+    Conceptually, we can think of this as @c@ automatically taking over the+    'Pipe''s channeling responsibilities when @a <+< b@ can no longer continue.+    There is no need to \"restart\" the input or output manually as in some+    other iteratee libraries.++    The @pipes@ library, unlike other iteratee libraries, grounds its vertical+    and horizontal concatenation in category theory by deriving horizontal+    concatenation ('.') from its 'Category' instance and vertical concatenation+    ('>>') from its 'Monad' instance.  This makes it easier to reason about+    'Pipe's because you can leverage your intuition about 'Category's and+    'Monad's to understand their behavior.  The only 'Pipe'-specific primitives+    are 'await' and 'yield'.+-}++{- $resource+    Here's another problem with 'Pipe' composition: resource finalization.+    Let's say we have the file \"@test.txt@\" with the following contents:++> Line 1+> Line 2+> Line 3++  .. and we wish to lazily read one line at a time from it:++> readFile' :: Handle -> Producer Text IO ()+> readFile' h = do+>     eof <- lift $ hIsEOF h+>     when (not eof) $ do+>         s <- lift $ hGetLine h+>         yield s+>         readFile' h++    We could then try to be slick and write a lazy version that only reads as+    many lines as we request:++> read' :: FilePath -> Producer Text IO ()+> read' file = do+>     lift $ putStrLn "Opening file ..."+>     h <- lift $ openFile file ReadMode+>     readFile' h+>     lift $ putStrLn "Closing file ..."+>     lift $ hClose h++    Now compose!++>>> runPipe $ printer <+< read' "test.xt"+Opening file ...+"Line 1"+"Line 2"+"Line 3"+Closing file ...++    So far, so good.  Equally important, the file is never opened if we replace+    @printer@ with a 'Pipe' that never demands input:++>>> runPipe $ (lift $ putStrLn "I don't need input") <+< read' "test.txt"+I don't need input++    There is still one problem, though. What if we wrote:++>>> runPipe $ printer <+< take' 2 <+< read' "test.txt"+Opening file ...+"Line 1"+"Line 2"+You shall not pass!++    Oh no!  While it was lazy and only read two lines from the file, it was also+    too lazy to properly close our file!  \"@take' 2@\" terminated before+    @read'@, preventing @read'@ from properly closing \"test.txt\".  This is why+    'Pipe' composition fails to guarantee deterministic finalization.+-}++{- $frames+    So with 'Pipe's, we can neither write folds, nor can we finalize resources+    deterministically.  Fortunately, there is a solution: 'Frame's.  Check out+    "Control.Frame.Tutorial" for an introduction to a type that enriches 'Pipe's+    with the ability to fold and finalize resources correctly.+-}
pipes.cabal view
@@ -1,5 +1,5 @@ Name: pipes-Version: 2.0.0+Version: 2.1.0 Cabal-Version: >=1.10.1 Build-Type: Simple License: BSD3@@ -39,20 +39,22 @@     Vertical Concatenation always works the way you expect, picking up where the     previous 'Pipe' left off.   .-  Check out "Control.Pipe" for a copious tutorial and "Control.Pipe.Common" for-  the actual implementation.+  Check out "Control.Pipe.Tutorial" for a copious introductory tutorial and+  "Control.Pipe" for the actual implementation. Category: Control, Enumerator-Tested-With: GHC ==7.0.3+Tested-With: GHC ==7.4.1 Source-Repository head     Type: git     Location: https://github.com/Gabriel439/Haskell-Pipes-Library  Library-    Build-Depends: base >= 4 && < 5, transformers, void+    Build-Depends: base >= 4 && < 5, transformers, void, index-core     Exposed-Modules:+        Control.Frame,+        Control.Frame.Tutorial,+        Control.IMonad.Trans.Free,+        Control.Monad.Trans.Free,         Control.Pipe,-        Control.Pipe.Common,-        Control.Pipe.Final,-        Control.Monad.Trans.Free+        Control.Pipe.Tutorial     GHC-Options: -O2     Default-Language: Haskell2010