-- 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. @package tubes @version 0.2.2.0 module Tubes.Core -- | A Tube is a computation which can -- --
-- 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 => Source b m () -> 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 -- --
-- 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 => Source b m () -> 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))