/      !"#$%&'()*+,-.Safe-345INA computation which only   s and never  s.A computation which only   s and never  sA  is a computation which can < an intermediate value downstream and suspend execution; and A a value from upstream, deferring execution until it is received.Moreover, individual s 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.w 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 tThe type signatures for the two value constructors should bear a strong resemblance to the actual type signature of J. Instead of encoding tubes as structures which build up when composed, a K is a control flow mechanism which picks one of two provided continuations.ePeople using this library should never have to contend with these details but it is worth mentioning.!Constructor for sink computations #Constructor for source computations This performs a neat trick: a  with a return type a will be turned into a new  containing the underlying  value.In this way the  and   functions can replace the ()k return value with a continuation and recursively traverse the computation until a final result is reached. (Command to wait for a new value upstream "Command to send a value downstream <Connect a task to a continuation yielding another task; see "Compose two tubes into a new tube. Enumerate  .ed values into a continuation, creating a new Infix version of Convert a list to a Insert a value into a /Implementation of " but without the type constraints. Connects a  to a , finishing when either the  is exhausted or the  terminates.01 /     01 /SafeIN2"Used in the case of a specialized O type and we know for certain a particular case will never actually be called.>Continuously relays any values it receives. Iteratee identity.:Transforms all incoming values according to some function.Refuses to yield the first n values it receives.-Yields only values satisfying some predicate.DTerminates the stream upon receiving a value violating the predicateRelay only the first n elements of a stream.)Taps the next value from a source, maybe.Strict left-fold of a stream. Note that the actual return type of the source is not relevant, only the intermediate yield type. Similar to 3 except it explicitly marks the stream as exhausted Similar to 9 except it maps a monadic function instead of a pure one.7Evaluates and extracts a pure value from a monadic one. Source of 3Cs from stdin. This is mostly for debugging / ghci example purposes.  Sink for 3Cs to stdout. This is mostly for debugging / ghci example purposes.42 step function initial valuefinal transformation stream source   42 Safe-479 5Lovingly stolen from Dan Piponi and David Laing. This models a poor man's adjunction: it allows adjoint functors to essentially annihilate one another and produce a final value.cIf this or something equivalent turns up in a separate package I will happily switch to using that.%A % is the dual to a . Intuitively, if a Tube- is a stream- processing computation, then a Pump( is both a stream generator and reducer.Examples may help!One interesting use of a Pump. is as a data stream, which can be fed into a Tube or Sink. * import Data.Functor.Identity e :: Pump (Maybe Int) Int Identity Int e = mkPump (Identity 0) (\(Identity x) -> (Just x, Identity (x+1))) const ex1 :: IO () ex1 = do run $ each e >< take 10 >< map show >< display -- displays 0-9 in the console A Pump may also be used to fold a Source . Indeed, a Pump may be thought of as both a non-recursive left fold and a non-recursive unfold paired together. (This is called a "metamorphism," hence the function "meta".) P num_src :: Source Int IO () num_src = do forM_ [1..] $ \n -> do lift . putStrLn $ "Yielding " ++ (show n) yield n enum_ex :: IO () enum_ex = do v <- reduce (flip send) (meta (+) 0 (\x -> (x,x))) extract $ num_src >< take 5 putStrLn . show $ "v = " ++ (show v) -- v = 15 !The following is an example of a Pump! both accumulating values from a Source" and then enumerating them into a SinkJ. This gives back both the result of the computation and the unused input. ) import Data.Functor.Identity -- a q that stops after 5 loops, or when input is exhausted sum_snk :: Sink (Maybe Int) IO Int sum_snk = do ns <- forM [1,2,3,4,5] $ \_ -> do mn <- await case mn of Just n -> return [n] Nothing -> return [] return $ sum . concat $ ns source_sink_ex :: IO ([Int], Int) source_sink_ex = do e <- reduce (flip send) (enumerator []) id $ num_src >< take 10 (unused, total) <- pump (,) e sum_snk putStrLn $ "Total: " ++ (show total) putStrLn $ "Unused: " ++ (show unused) -- "Total: 15" -- "Unused: [6,7,8,9,10]" Note that when a Pump and a Tube are combined with - , that the Tube determines control flow. Pumps are comonads, not monads.DThere are doubtless more and more interesting examples of combining Tubes and Pump/s. If you think of any, drop the author a line!&DRuns a tube computation, producing a result value in the base monad.;Because of higher-rank polymorphism, tubes created using a  and & will work with this function as well."Similarly, any tube created using  and a @ will work as well. This is an improvement over the behavior of ! which gives back an unevaluated 6 tree.An example (using num_src and src_snk+ defined previously in this documentation):  num_src :: Source Int IO () num_src = do forM_ [1..] $ \n -> do lift . putStrLn $ "Yielding " ++ (show n) yield n sum_snk :: Sink (Maybe Int) IO Int sum_snk = do ns <- forM [1,2,3,4,5] $ \_ -> do mn <- await case mn of Just n -> return [n] Nothing -> return [] return $ sum . concat $ ns >>> run $ num_src |> sum_snk 15 15 is the return value from sum_snkP. Both the source and the sink have the ability to terminate the computation by 7>ing, perhaps when the source is exhausted or the sink is full.' Creates a % for a z 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 d may be altered and sent back into the tube, hence this mechanism does act like something of a pump.(Pull a value from a %, along with the rest of the %.)Send a value into a %$, effectively re-seeding the stream.*Using the supplied functions, *H will fold and then unfold a stream, hence its name (which is short for  metamorphism).+[Constructs an enumerator pump, which can buffer values and then enumerate them to, say, a  (see the examples above)., Transforms a % into a corresponding .-Given a suitably matching  and %/, you can use the latter to execute the former.. A variant of -= which allows effects to be executed inside the pump as well.58!"#$%&'()*+,9:-.;<=>?!"#$%&'()*+,-.%!"#$&'()-.*+,58!"#$%&'()*+,9:-.;<=>?All-encompassing module.1(c) 2014, 2015 Gatlin Johnson <gatlin@niltag.net>GPL-3gatlin@niltag.net experimentalSafe-  !"#$%&'()*+,-.-&    %!"#$')(-.*+,@     !"#$%&'())*+,-./01234567889:;7< =9:>?@ABCDEFGtubes_2ya09oNYsTbJZWSmqbPr2bTubes Tubes.Core Tubes.Util Tubes.Pumptrans_3eG64VdP2vzGjP6wJiCp5XControl.Monad.Trans.Classliftfree_LKDmtZBjLxFCi7vXcV3rcyControl.Monad.Trans.FreerunFreeTSinkSourceTubeTubeFrunTawaitFyieldFliftTawaityield>-><for~>each-<|>catmapdropfilter takeWhiletakeunyieldreduceeverymapMsequencepromptdisplayPumpFrecvFsendFPumprunmkPumprecvsendmeta enumerator enumeratepumppumpM\|>fixdivergebaseGHC.BaseStringPairingFreeTreturnpair pairEffect pairEffectM$fPairingPumpFTubeF$fPairing(,)(->)$fPairing(->)(,)$fPairingIdentityIdentity$fFoldablePumpF