úÎt\q./      !"#$%&'()*+,-.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.   is shorter than , and who knows, maybe it'll change some day (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 5±Lovingly 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".) ÿN 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 ÿp 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!' 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.*iTakes a fold function, an initial value, and an unfold to produce a metamorphism. Can be used to change.+[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.56"#$%&'()*+,78-.9:;<= "#$%&'()*+,-. &"#$%'()-.*+,56"#$%&'()*+,78-.9:;<=All-encompassing module.1(c) 2014, 2015 Gatlin Johnson <gatlin@niltag.net>GPL-3gatlin@niltag.net experimentalSafe-  !"#$%&'()*+,-.-   !&"#$%')(-.*+,>     !"#$%&'()**+,-./01234567889:;7<=>?@ABCDEtubes_KYD0TPVkcviCiz59HJFkKRTubes Tubes.Core Tubes.Util Tubes.Pumptrans_ALYlebOVzVI4kxbFX5SGhmControl.Monad.Trans.Classliftfree_BZnOVEjFqDE2rr9FZiux0dControl.Monad.Trans.FreerunFreeTSinkSourceTubeTubeFrunTawaitFyieldFliftTrunawaityield>-><for~>each-<|>catmapdropfilter takeWhiletakeunyieldreduceeverymapMsequencepromptdisplayPumpFrecvFsendFPumpmkPumprecvsendmeta enumerator enumeratepumppumpM\|>fixdivergebaseGHC.BaseStringPairingpair pairEffect pairEffectM$fPairingPumpFTubeF$fPairing(,)(->)$fPairing(->)(,)$fPairingIdentityIdentity$fFoldablePumpF