-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Effectful, iteratee-inspired stream processing based on a -- free monad. -- -- This package provides the Tube monad transformer, allowing -- any monad computation to become a stream processing pipeline. A -- computation of type Tube a b m r consumes values of type -- a and produces values of type b. -- -- Tubes are coroutines which can suspend computation to yield -- an intermediate value or continue execution by requesting an upstream -- value. -- -- Examples and more information may be found at -- https://github.com/gatlin/tubes. -- -- If I managed to upload another faulty package that does not build -- correctly, Hackage documentation is also available at -- http://niltag.net/tubes. This should compile on GHC 7.8, but -- the problem is that previous attempts at setting the versions properly -- rendered Hackage unable to generate documentation. Hopefully I have -- this fixed but any advice is welcome. @package tubes @version 0.2.2.3 module Tubes.Core -- | A Tube is a computation which can -- -- -- -- Moreover, individual Tubes may be freely composed into larger -- ones, so long as their types match. Thus, one may write small, -- reusable building blocks and construct efficient stream process -- pipelines. -- -- Since a much better engineered, more popular, and decidedly more -- mature library already uses the term "pipes" I have opted instead to -- think of my work as a series of tubes. type Tube a b = FreeT (TubeF a b) -- | TubeF is the union of unary functions and binary products into -- a single type, here defined with a Boehm-Berarducci encoding. -- -- This type is equivalent to the following: -- --
--   data TubeF a b k
--       = Await (a -> k) -- :: (a -> k) -> TubeF a b k
--       | Yield (b  , k) -- :: (b  , k) -> TubeF a b k
--   
--   
-- -- The type signatures for the two value constructors should bear a -- strong resemblance to the actual type signature of runT. -- Instead of encoding tubes as structures which build up when composed, -- a TubeF is a control flow mechanism which picks one of two -- provided continuations. -- -- People using this library should never have to contend with these -- details but it is worth mentioning. newtype TubeF a b k TubeF :: (forall r. ((a -> k) -> r) -> ((b, k) -> r) -> r) -> TubeF a b k [runT] :: TubeF a b k -> forall r. ((a -> k) -> r) -> ((b, k) -> r) -> r -- | A computation which only yields and never awaits type Source b m r = forall x. Tube x b m r -- | A computation which only awaits and never yields. type Sink a m r = forall x. Tube a x m r -- | run is shorter than runFreeT and who knows, maybe it'll -- change some day run :: FreeT f m a -> m (FreeF f a (FreeT f m a)) -- | Command to wait for a new value upstream await :: Monad m => Tube a b m a -- | Command to send a value downstream yield :: Monad m => b -> Tube a b m () -- | Convert a list to a Source each :: (Monad m, Foldable t) => t b -> Tube a b m () -- | Enumerate yielded values into a continuation, creating a new -- Source for :: Monad m => Tube a b m r -> (b -> Tube a c m s) -> Tube a c m r -- | Compose two tubes into a new tube. (><) :: Monad m => Tube a b m r -> Tube b c m r -> Tube a c m r -- | Connect a task to a continuation yielding another task; see -- >< (>-) :: Monad m => Tube a b m r -> (b -> Tube b c m r) -> Tube a c m r -- | Infix version of for (~>) :: Monad m => Tube a b m r -> (b -> Tube a c m s) -> Tube a c m r -- | Insert a value into a Sink (-<) :: Monad m => a -> Sink a m b -> Sink a m b -- | Connects a Source to a Sink, finishing when either the -- Source is exhausted or the Sink terminates. (|>) :: Monad m => Tube x b m r -> Sink (Maybe b) m s -> Sink (Maybe b) m s -- | Constructor for source computations yieldF :: b -> k -> TubeF a b k -- | Constructor for sink computations awaitF :: (a -> k) -> TubeF a b k -- | This performs a neat trick: a Tube with a return type -- a will be turned into a new Tube containing the -- underlying TubeF value. -- -- In this way the >< and >- functions can replace -- the () return value with a continuation and recursively -- traverse the computation until a final result is reached. liftT :: (MonadTrans t, Monad m) => FreeT f m a -> t m (FreeF f a (FreeT f m a)) instance GHC.Base.Functor (Tubes.Core.TubeF a b) module Tubes.Util -- | Continuously relays any values it receives. Iteratee identity. cat :: Monad m => Tube a a m r -- | Transforms all incoming values according to some function. map :: (Monad m) => (a -> b) -> Tube a b m r -- | Refuses to yield the first n values it receives. drop :: Monad m => Int -> Tube a a m r -- | Relay only the first n elements of a stream. take :: Monad m => Int -> Tube a a m () -- | Terminates the stream upon receiving a value violating the predicate takeWhile :: Monad m => (a -> Bool) -> Tube a a m () -- | Yields only values satisfying some predicate. filter :: Monad m => (a -> Bool) -> Tube a a m r -- | Strict left-fold of a stream. Note that the actual return type of the -- source is not relevant, only the intermediate yield type. reduce :: Monad m => (x -> a -> x) -> x -> (x -> b) -> Source a m () -> m b -- | Similar to each except it explicitly marks the stream as -- exhausted every :: (Foldable t, Monad m) => t b -> Tube a (Maybe b) m () -- | Source of Strings from stdin. This is mostly for debugging / -- ghci example purposes. prompt :: Source String IO () -- | Sink for Strings to stdout. This is mostly for debugging / ghci -- example purposes. display :: Sink String IO () -- | Taps the next value from a source, maybe. unyield :: Monad m => FreeT (TubeF x b) m () -> m (Maybe (b, FreeT (TubeF x b) m ())) module Tubes.Pump -- | A Pump is the dual to a Tube: where a Tube is a -- computation manipulating a stream of values, a Pump can be -- situated on either end of a tube to both insert values when requested -- and handle any yielded results. -- -- One interesting use of a Pump is to feed data to a Tube, -- collecting the result as well as unused input: -- --
--   import Data.Functor.Identity
--   
--   p :: [a] -> Pump (Maybe a) x Identity [a]
--   p inp = pump (return inp)
--           (wa -> case (extract wa) of
--               [] -> (Nothing, wa)
--               x:xs -> (Just x, return xs))
--           const
--   
--   -- a Sink that stops after 5 loops, or when input is exhausted
--   add5 :: Sink (Maybe Int) IO Int
--   add5 = loop 0 5 where
--       loop acc ct = if 0 == ct
--           then return acc
--           else do
--               mn <- await
--               maybe (return acc)
--                     (n -> loop (acc+n) (ct - 1))
--                     mn
--   
--   result :: IO ([Int], Int)
--   result = runPump (curry id) (p [1..10]) add5
--   -- ([6,7,8,9,10],15)
--   
--   
-- -- Pumps are still being investigated by the author so if you come -- up with something interesting, please share! type Pump a b = CofreeT (PumpF a b) data PumpF a b k PumpF :: (a, k) -> (b -> k) -> PumpF a b k [recvF] :: PumpF a b k -> (a, k) [sendF] :: PumpF a b k -> (b -> k) -- | Creates a Pump for a Tube using a comonadic seed value, -- a function to give it more data upon request, and a function to handle -- any yielded results. -- -- Values received from the Tube may be altered and sent back into -- the tube, hence this mechanism does act like something of a pump. pump :: Comonad w => w a -> (w a -> (b, w a)) -> (w a -> c -> w a) -> Pump b c w a -- | Pull a value from a Pump, along with the rest of the -- Pump. recv :: Comonad w => Pump a b w r -> (a, Pump a b w r) -- | Send a value into a Pump, effectively re-seeding the stream. send :: Comonad w => Pump a b w r -> b -> Pump a b w r -- | Given a suitably matching Tube and Pump, you can use the -- latter to execute the former. runPump :: (Comonad w, Monad m) => (x -> y -> r) -> Pump a b w x -> Tube a b m y -> m r instance GHC.Base.Functor (Tubes.Pump.PumpF a b) instance Tubes.Pump.Pairing Data.Functor.Identity.Identity Data.Functor.Identity.Identity instance Tubes.Pump.Pairing ((->) a) ((,) a) instance Tubes.Pump.Pairing ((,) a) ((->) a) instance Tubes.Pump.Pairing (Tubes.Pump.PumpF a b) (Tubes.Core.TubeF a b) -- | Write effect-ful stream processing functions and compose them into a -- series of tubes. -- -- This exists primarily for my own education. It is updated often as I -- try things and is probably, at this moment, wrong. -- -- My goals were to -- -- module Tubes -- | A Tube is a computation which can -- -- -- -- Moreover, individual Tubes may be freely composed into larger -- ones, so long as their types match. Thus, one may write small, -- reusable building blocks and construct efficient stream process -- pipelines. -- -- Since a much better engineered, more popular, and decidedly more -- mature library already uses the term "pipes" I have opted instead to -- think of my work as a series of tubes. type Tube a b = FreeT (TubeF a b) -- | TubeF is the union of unary functions and binary products into -- a single type, here defined with a Boehm-Berarducci encoding. -- -- This type is equivalent to the following: -- --
--   data TubeF a b k
--       = Await (a -> k) -- :: (a -> k) -> TubeF a b k
--       | Yield (b  , k) -- :: (b  , k) -> TubeF a b k
--   
--   
-- -- The type signatures for the two value constructors should bear a -- strong resemblance to the actual type signature of runT. -- Instead of encoding tubes as structures which build up when composed, -- a TubeF is a control flow mechanism which picks one of two -- provided continuations. -- -- People using this library should never have to contend with these -- details but it is worth mentioning. newtype TubeF a b k TubeF :: (forall r. ((a -> k) -> r) -> ((b, k) -> r) -> r) -> TubeF a b k [runT] :: TubeF a b k -> forall r. ((a -> k) -> r) -> ((b, k) -> r) -> r -- | A computation which only yields and never awaits type Source b m r = forall x. Tube x b m r -- | A computation which only awaits and never yields. type Sink a m r = forall x. Tube a x m r -- | run is shorter than runFreeT and who knows, maybe it'll -- change some day run :: FreeT f m a -> m (FreeF f a (FreeT f m a)) -- | Command to wait for a new value upstream await :: Monad m => Tube a b m a -- | Command to send a value downstream yield :: Monad m => b -> Tube a b m () -- | Convert a list to a Source each :: (Monad m, Foldable t) => t b -> Tube a b m () -- | Enumerate yielded values into a continuation, creating a new -- Source for :: Monad m => Tube a b m r -> (b -> Tube a c m s) -> Tube a c m r -- | Infix version of for (~>) :: Monad m => Tube a b m r -> (b -> Tube a c m s) -> Tube a c m r -- | Connect a task to a continuation yielding another task; see -- >< (>-) :: Monad m => Tube a b m r -> (b -> Tube b c m r) -> Tube a c m r -- | Compose two tubes into a new tube. (><) :: Monad m => Tube a b m r -> Tube b c m r -> Tube a c m r -- | Connects a Source to a Sink, finishing when either the -- Source is exhausted or the Sink terminates. (|>) :: Monad m => Tube x b m r -> Sink (Maybe b) m s -> Sink (Maybe b) m s -- | Insert a value into a Sink (-<) :: Monad m => a -> Sink a m b -> Sink a m b -- | This performs a neat trick: a Tube with a return type -- a will be turned into a new Tube containing the -- underlying TubeF value. -- -- In this way the >< and >- functions can replace -- the () return value with a continuation and recursively -- traverse the computation until a final result is reached. liftT :: (MonadTrans t, Monad m) => FreeT f m a -> t m (FreeF f a (FreeT f m a)) -- | Continuously relays any values it receives. Iteratee identity. cat :: Monad m => Tube a a m r -- | Transforms all incoming values according to some function. map :: (Monad m) => (a -> b) -> Tube a b m r -- | Refuses to yield the first n values it receives. drop :: Monad m => Int -> Tube a a m r -- | Relay only the first n elements of a stream. take :: Monad m => Int -> Tube a a m () -- | Terminates the stream upon receiving a value violating the predicate takeWhile :: Monad m => (a -> Bool) -> Tube a a m () -- | Yields only values satisfying some predicate. filter :: Monad m => (a -> Bool) -> Tube a a m r -- | Strict left-fold of a stream. Note that the actual return type of the -- source is not relevant, only the intermediate yield type. reduce :: Monad m => (x -> a -> x) -> x -> (x -> b) -> Source a m () -> m b -- | Similar to each except it explicitly marks the stream as -- exhausted every :: (Foldable t, Monad m) => t b -> Tube a (Maybe b) m () -- | Taps the next value from a source, maybe. unyield :: Monad m => FreeT (TubeF x b) m () -> m (Maybe (b, FreeT (TubeF x b) m ())) -- | Source of Strings from stdin. This is mostly for debugging / -- ghci example purposes. prompt :: Source String IO () -- | Sink for Strings to stdout. This is mostly for debugging / ghci -- example purposes. display :: Sink String IO () -- | A Pump is the dual to a Tube: where a Tube is a -- computation manipulating a stream of values, a Pump can be -- situated on either end of a tube to both insert values when requested -- and handle any yielded results. -- -- One interesting use of a Pump is to feed data to a Tube, -- collecting the result as well as unused input: -- --
--   import Data.Functor.Identity
--   
--   p :: [a] -> Pump (Maybe a) x Identity [a]
--   p inp = pump (return inp)
--           (wa -> case (extract wa) of
--               [] -> (Nothing, wa)
--               x:xs -> (Just x, return xs))
--           const
--   
--   -- a Sink that stops after 5 loops, or when input is exhausted
--   add5 :: Sink (Maybe Int) IO Int
--   add5 = loop 0 5 where
--       loop acc ct = if 0 == ct
--           then return acc
--           else do
--               mn <- await
--               maybe (return acc)
--                     (n -> loop (acc+n) (ct - 1))
--                     mn
--   
--   result :: IO ([Int], Int)
--   result = runPump (curry id) (p [1..10]) add5
--   -- ([6,7,8,9,10],15)
--   
--   
-- -- Pumps are still being investigated by the author so if you come -- up with something interesting, please share! type Pump a b = CofreeT (PumpF a b) data PumpF a b k PumpF :: (a, k) -> (b -> k) -> PumpF a b k [recvF] :: PumpF a b k -> (a, k) [sendF] :: PumpF a b k -> (b -> k) -- | Creates a Pump for a Tube using a comonadic seed value, -- a function to give it more data upon request, and a function to handle -- any yielded results. -- -- Values received from the Tube may be altered and sent back into -- the tube, hence this mechanism does act like something of a pump. pump :: Comonad w => w a -> (w a -> (b, w a)) -> (w a -> c -> w a) -> Pump b c w a -- | Send a value into a Pump, effectively re-seeding the stream. send :: Comonad w => Pump a b w r -> b -> Pump a b w r -- | Pull a value from a Pump, along with the rest of the -- Pump. recv :: Comonad w => Pump a b w r -> (a, Pump a b w r) -- | Given a suitably matching Tube and Pump, you can use the -- latter to execute the former. runPump :: (Comonad w, Monad m) => (x -> y -> r) -> Pump a b w x -> Tube a b m y -> m r -- | Lift a computation from the argument monad to the constructed monad. lift :: MonadTrans t => forall (m :: * -> *) a. Monad m => m a -> t m a runFreeT :: FreeT f m a -> m (FreeF f a (FreeT f m a))