packages feed

churros 0.1.2.0 → 0.1.3.0

raw patch · 10 files changed

+158/−117 lines, 10 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Control.Churro.Types: instance Control.Churro.Types.Transport t => Control.Arrow.Arrow (Control.Churro.Types.Churro t)
- Control.Churro.Types: instance Control.Churro.Types.Transport t => Control.Category.Category (Control.Churro.Types.Churro t)
- Control.Churro.Types: instance Control.Churro.Types.Transport t => GHC.Base.Applicative (Control.Churro.Types.Churro t Data.Void.Void)
- Control.Churro.Types: instance Control.Churro.Types.Transport t => GHC.Base.Functor (Control.Churro.Types.Churro t i)
+ Control.Churro.Prelude: sinkHO :: Transport t => (((i -> IO ()) -> IO ()) -> IO a) -> Churro a t i o
+ Control.Churro.Prelude: sink_ :: Transport t => Churro () t i Void
+ Control.Churro.Prelude: sources_ :: Transport t => [Source () t o] -> Source () t o
+ Control.Churro.Types: (>>>>) :: (Transport t, fo ~ gi) => Churro a1 t fi fo -> Churro a2 t gi go -> Churro a2 t fi go
+ Control.Churro.Types: arr' :: (Functor (cat a), Category cat) => (a -> b) -> cat a b
+ Control.Churro.Types: instance (Control.Churro.Types.Transport t, GHC.Base.Monoid a) => Control.Category.Category (Control.Churro.Types.Churro a t)
+ Control.Churro.Types: instance Control.Churro.Types.Transport t => Control.Arrow.Arrow (Control.Churro.Types.Churro () t)
+ Control.Churro.Types: instance Control.Churro.Types.Transport t => GHC.Base.Applicative (Control.Churro.Types.Churro () t Data.Void.Void)
+ Control.Churro.Types: instance Control.Churro.Types.Transport t => GHC.Base.Functor (Control.Churro.Types.Churro a t i)
+ Control.Churro.Types: pure' :: (Transport t, Monoid a) => o -> Churro a t i o
- Control.Churro.Prelude: delay :: Transport t => NominalDiffTime -> Churro t a a
+ Control.Churro.Prelude: delay :: Transport t => NominalDiffTime -> Churro () t a a
- Control.Churro.Prelude: delayMicro :: Transport t => Int -> Churro t a a
+ Control.Churro.Prelude: delayMicro :: Transport t => Int -> Churro () t a a
- Control.Churro.Prelude: dropC :: (Transport t, Integral n) => n -> Churro t a a
+ Control.Churro.Prelude: dropC :: (Transport t, Integral n) => n -> Churro () t a a
- Control.Churro.Prelude: filterC :: Transport t => (a -> Bool) -> Churro t a a
+ Control.Churro.Prelude: filterC :: Transport t => (a -> Bool) -> Churro () t a a
- Control.Churro.Prelude: justs :: Transport t => Churro t (Maybe a) a
+ Control.Churro.Prelude: justs :: Transport t => Churro () t (Maybe a) a
- Control.Churro.Prelude: lefts :: Transport t => Churro t (Either a b) a
+ Control.Churro.Prelude: lefts :: Transport t => Churro () t (Either a b) a
- Control.Churro.Prelude: mapN :: Transport t => (a -> [b]) -> Churro t a b
+ Control.Churro.Prelude: mapN :: Transport t => (a -> [b]) -> Churro () t a b
- Control.Churro.Prelude: process :: Transport t => (a -> IO b) -> Churro t a b
+ Control.Churro.Prelude: process :: Transport t => (a -> IO b) -> Churro () t a b
- Control.Churro.Prelude: processDebug :: (Transport t, Show b) => String -> Churro t b b
+ Control.Churro.Prelude: processDebug :: (Transport t, Show b) => String -> Churro () t b b
- Control.Churro.Prelude: processN :: Transport t => (a -> IO [b]) -> Churro t a b
+ Control.Churro.Prelude: processN :: Transport t => (i -> IO [o]) -> Churro () t i o
- Control.Churro.Prelude: processPrint :: (Transport t, Show b) => Churro t b b
+ Control.Churro.Prelude: processPrint :: (Transport t, Show b) => Churro () t b b
- Control.Churro.Prelude: processRetry :: Transport t => Natural -> (i -> IO o) -> Churro t i o
+ Control.Churro.Prelude: processRetry :: Transport t => Natural -> (i -> IO o) -> Churro () t i o
- Control.Churro.Prelude: processRetry' :: (Exception e, Transport t) => Natural -> (i -> IO o) -> Churro t i (Either e o)
+ Control.Churro.Prelude: processRetry' :: (Exception e, Transport t) => Natural -> (i -> IO o) -> Churro () t i (Either e o)
- Control.Churro.Prelude: processRetry'' :: (Transport t, Exception e, Ord n, Enum n) => n -> (a -> IO b) -> Churro t (n, a) (Either e b)
+ Control.Churro.Prelude: processRetry'' :: (Transport t, Exception e, Ord n, Enum n) => n -> (a -> IO b) -> Churro () t (n, a) (Either e b)
- Control.Churro.Prelude: rights :: Transport t => Churro t (Either a b) b
+ Control.Churro.Prelude: rights :: Transport t => Churro () t (Either a b) b
- Control.Churro.Prelude: run :: Transport t => Churro t Void Void -> IO (Async ())
+ Control.Churro.Prelude: run :: Transport t => Churro a t Void Void -> IO (Async a)
- Control.Churro.Prelude: run' :: Transport t => Churro t i o -> IO (Async ())
+ Control.Churro.Prelude: run' :: Transport t => Churro a t i o -> IO (Async a)
- Control.Churro.Prelude: runWait :: Transport t => Churro t Void Void -> IO ()
+ Control.Churro.Prelude: runWait :: Transport t => Churro a t Void Void -> IO a
- Control.Churro.Prelude: runWaitList :: Transport t => Churro t Void o -> IO [o]
+ Control.Churro.Prelude: runWaitList :: (Transport t, Monoid a) => Churro a t Void b -> IO [b]
- Control.Churro.Prelude: sink :: Transport t => Churro t b Void
+ Control.Churro.Prelude: sink :: (Transport t, Monoid a) => Churro a t a Void
- Control.Churro.Prelude: sinkIO :: Transport t => (o -> IO ()) -> Churro t o Void
+ Control.Churro.Prelude: sinkIO :: (Transport t, Monoid a) => (o -> IO a) -> Churro a t o Void
- Control.Churro.Prelude: sinkPrint :: (Transport t, Show a) => Churro t a Void
+ Control.Churro.Prelude: sinkPrint :: (Transport t, Show a) => Churro () t a Void
- Control.Churro.Prelude: sourceIO :: Transport t => ((o -> IO ()) -> IO ()) -> Churro t Void o
+ Control.Churro.Prelude: sourceIO :: Transport t => ((o -> IO ()) -> IO a) -> Churro a t Void o
- Control.Churro.Prelude: sourceList :: (Transport t, Foldable f) => f o -> Churro t Void o
+ Control.Churro.Prelude: sourceList :: (Transport t, Foldable f) => f o -> Churro () t Void o
- Control.Churro.Prelude: sourceSingleton :: Transport t => o -> Churro t Void o
+ Control.Churro.Prelude: sourceSingleton :: Transport t => o -> Churro () t Void o
- Control.Churro.Prelude: sources :: Transport t => [Source t o] -> Source t o
+ Control.Churro.Prelude: sources :: (Transport t, Monoid a) => [Source a t o] -> Source () t o
- Control.Churro.Prelude: takeC :: (Transport t, Integral n) => n -> Churro t a a
+ Control.Churro.Prelude: takeC :: (Transport t, Integral n) => n -> Churro () t a a
- Control.Churro.Prelude: withPrevious :: Transport t => Churro t a (a, a)
+ Control.Churro.Prelude: withPrevious :: Transport t => Churro () t a (a, a)
- Control.Churro.Transport.Chan: runWaitChan :: ChurroChan Void Void -> IO ()
+ Control.Churro.Transport.Chan: runWaitChan :: ChurroChan a Void Void -> IO a
- Control.Churro.Transport.Chan: runWaitListChan :: ChurroChan Void o -> IO [o]
+ Control.Churro.Transport.Chan: runWaitListChan :: ChurroChan () Void o -> IO [o]
- Control.Churro.Transport.Chan: type ChurroChan = Churro Chan
+ Control.Churro.Transport.Chan: type ChurroChan a = Churro a Chan
- Control.Churro.Transport.Unagi: runWaitListUnagi :: ChurroUnagi Void o -> IO [o]
+ Control.Churro.Transport.Unagi: runWaitListUnagi :: ChurroUnagi () Void o -> IO [o]
- Control.Churro.Transport.Unagi: runWaitUnagi :: ChurroUnagi Void Void -> IO ()
+ Control.Churro.Transport.Unagi: runWaitUnagi :: ChurroUnagi a Void Void -> IO a
- Control.Churro.Transport.Unagi: type ChurroUnagi = Churro Unagi
+ Control.Churro.Transport.Unagi: type ChurroUnagi a = Churro a Unagi
- Control.Churro.Transport.Unagi.Bounded: runWaitListUnagi :: KnownNat n => ChurroUnagiBounded n Void o -> IO [o]
+ Control.Churro.Transport.Unagi.Bounded: runWaitListUnagi :: KnownNat n => ChurroUnagiBounded () n Void o -> IO [o]
- Control.Churro.Transport.Unagi.Bounded: runWaitUnagi :: KnownNat n => ChurroUnagiBounded n Void Void -> IO ()
+ Control.Churro.Transport.Unagi.Bounded: runWaitUnagi :: KnownNat n => ChurroUnagiBounded a n Void Void -> IO a
- Control.Churro.Transport.Unagi.Bounded: type ChurroUnagiBounded n = Churro (UnagiBounded n)
+ Control.Churro.Transport.Unagi.Bounded: type ChurroUnagiBounded a n = Churro a (UnagiBounded n)
- Control.Churro.Types: Churro :: IO (In t (Maybe i), Out t (Maybe o), Async ()) -> Churro t i o
+ Control.Churro.Types: Churro :: IO (In t (Maybe i), Out t (Maybe o), Async a) -> Churro a t i o
- Control.Churro.Types: [runChurro] :: Churro t i o -> IO (In t (Maybe i), Out t (Maybe o), Async ())
+ Control.Churro.Types: [runChurro] :: Churro a t i o -> IO (In t (Maybe i), Out t (Maybe o), Async a)
- Control.Churro.Types: buildChurro :: Transport t => (Out t (Maybe i) -> In t (Maybe o) -> IO ()) -> Churro t i o
+ Control.Churro.Types: buildChurro :: Transport t => (Out t (Maybe i) -> In t (Maybe o) -> IO a) -> Churro a t i o
- Control.Churro.Types: buildChurro' :: Transport t => (In t (Maybe i) -> Out t (Maybe i) -> In t (Maybe o) -> IO ()) -> Churro t i o
+ Control.Churro.Types: buildChurro' :: Transport t => (In t (Maybe i) -> Out t (Maybe i) -> In t (Maybe o) -> IO a) -> Churro a t i o
- Control.Churro.Types: data Churro t i o
+ Control.Churro.Types: data Churro a t i o
- Control.Churro.Types: type DoubleDipped t = Churro t Void Void
+ Control.Churro.Types: type DoubleDipped a t = Churro a t Void Void
- Control.Churro.Types: type Sink t i = Churro t i Void
+ Control.Churro.Types: type Sink a t i = Churro a t i Void
- Control.Churro.Types: type Source t o = Churro t Void o
+ Control.Churro.Types: type Source a t o = Churro a t Void o
- Control.Churro.Types: yankAll :: Transport t => Out t (Maybe i) -> (i -> IO a) -> IO ()
+ Control.Churro.Types: yankAll :: (Transport t, Monoid a) => Out t (Maybe i) -> (i -> IO a) -> IO a
- Control.Churro.Types: yankAll' :: Transport t => Out t (Maybe a) -> (Maybe a -> IO b) -> IO b
+ Control.Churro.Types: yankAll' :: (Transport t, Monoid b) => Out t (Maybe a) -> (Maybe a -> IO b) -> IO b

Files

CHANGELOG.md view
@@ -1,5 +1,9 @@ # Revision history for Churros +## 0.1.3.0 -- 2020-10-17++* Generalised functions to have Monoid for Async action result.+ ## 0.1.2.0 -- 2020-10-15  * Added type families to transport class to allow for different in/out types
README.md view
@@ -13,13 +13,13 @@ Signup Example:  ```-New-Users {-> ID} ---> Validate {ID -> (ID,Email} ?--> Deploy {Email -> Port} --?-> Log {Port|Receipt ->}------------------      -------------------------- |    ----------------------   |   ----------------------    Subscribe                 REST Request        |          Run Server         |        Write File-                                                  |                             |-                                                  +--> Warn {Email -> Receipt} -+-                                                       ------------------------                                                             Send Email+New-Users -->  Validate -------?----->  Deploy  -----?--------------> Log+Subscribe    REST Request      |      Run Server     |         Write File+{-> ID}    {ID -> (ID,Email}   |    {Email -> Port}  |  {Port|Receipt ->}+                               |                     |+                               +-------> Warn -------++                                      Send Email+                                  {Email -> Receipt} ```  Developed from a history of attempting to use co-routines libraries for setting up complicated asynchronous processes@@ -37,7 +37,7 @@ Disadvantages:  * No pure interface!-* No expressive return type for the async action representing the background process is encoded in the Churro datatype (could this be addressed?)+* Type for the async action restricted to Monoid for most operations. * Limited ability to perform lock-step computation (although this is by design)  See [Hackage](https://hackage.haskell.org/package/churros-0.1.0.0/candidate) for more info!
churros.cabal view
@@ -1,6 +1,6 @@ cabal-version:       2.2 name:                churros-version:             0.1.2.0+version:             0.1.3.0 license-file:        LICENSE author:              Lyndon Maydwell maintainer:          lyndon@sordina.net
src/Control/Churro/Prelude.hs view
@@ -18,7 +18,6 @@ import           Control.Exception        (Exception, SomeException, try) import           Control.Monad            (replicateM_, when) import           Data.Foldable            (for_)-import           Data.IORef               (newIORef, readIORef, writeIORef) import           Data.Maybe               (isJust) import           Data.Time                (NominalDiffTime) import           Data.Void                (Void)@@ -29,6 +28,7 @@ --  -- The examples in this module require the following imports: -- +-- >>> :set -XBlockArguments -- >>> import Control.Churro.Transport -- >>> import Data.Time.Clock -- @@ -37,7 +37,7 @@  -- | Automatically wait for a churro to complete. -- -runWait :: Transport t => Churro t Void Void -> IO ()+runWait :: Transport t => Churro a t Void Void -> IO a runWait x = wait =<< run x  -- | Read the output of a Churro into a list.@@ -50,32 +50,21 @@ -- >>> runWaitListChan $ sourceList [0..4] >>> arr succ -- [1,2,3,4,5] -- -runWaitList :: Transport t => Churro t Void o -> IO [o]-runWaitList x = do-    t <- newIORef []--    let-        c = buildChurro \i _o -> do-            l <- yankList i-            writeIORef t l--    runWait $ x >>> c--    readIORef t+runWaitList :: (Transport t, Monoid a) => Churro a t Void b -> IO [b]+runWaitList c = runWait $ (c >>> arr' (:[])) >>>> sink   -- | Run a sourced and sinked (double-dipped) churro and return an async action representing the in-flight processes.--- -run :: Transport t => Churro t Void Void -> IO (Async ())+--+run :: Transport t => Churro a t Void Void -> IO (Async a) run = run'  -- | Run any churro, there is no check that this was spawned with a source, or terminated with a sink. --   This is unsafe, since the pipeline may not generate or consume in a predictable way. --   Use `run` instead unless you are confident you know what you're doing. -- -run' :: Transport t => Churro t i o -> IO (Async ())+run' :: Transport t => Churro a t i o -> IO (Async a) run' c = do-    -- Compose an empty sourceList to ensure termination-    (_i,_o,a) <- runChurro (sourceList [] >>> c)+    (_i,_o,a) <- runChurro c     return a  -- * Library@@ -91,7 +80,7 @@ --  -- >>> runWaitChan $ pure 23 >>> sinkPrint -- 23-sourceSingleton :: Transport t => o -> Churro t Void o+sourceSingleton :: Transport t => o -> Churro () t Void o sourceSingleton x = sourceList [x]  -- | Create a source from a list of items, sending each down the churro independently.@@ -99,7 +88,7 @@ -- >>> runWaitChan $ sourceList [4,2] >>> sinkPrint -- 4 -- 2-sourceList :: (Transport t, Foldable f) => f o -> Churro t Void o+sourceList :: (Transport t, Foldable f) => f o -> Churro () t Void o sourceList = sourceIO . for_  -- | Create a source from an IO action that is passed a function to yield new items.@@ -107,50 +96,89 @@ -- >>> runWaitChan $ sourceIO (\cb -> cb 4 >> cb 2) >>> sinkPrint -- 4 -- 2-sourceIO :: Transport t => ((o -> IO ()) -> IO ()) -> Churro t Void o+sourceIO :: Transport t => ((o -> IO ()) -> IO a) -> Churro a t Void o sourceIO cb =     buildChurro \_i o -> do-        cb (yeet o . Just)+        r <- cb (yeet o . Just)         yeet o Nothing+        return r  -- | Combine a list of sources into a single source. --  -- Sends individual items downstream without attempting to combine them. -- --- >>> runWaitChan $ sources [pure 1, pure 1] >>> sinkPrint+-- Warning: Passing an empty list is unspecified.+-- +-- TODO: Use NonEmptyList instead of []+-- +-- >>> runWaitChan $ sources_ [pure 1, pure 1] >>> sinkPrint -- 1 -- 1-sources :: Transport t => [Source t o] -> Source t o+sources :: (Transport t, Monoid a) => [Source a t o] -> Source () t o sources ss = sourceIO \cb -> do-    asyncs <- mapM (\s -> run $ s >>> sinkIO cb) ss-    (a, _) <- waitAny asyncs-    wait a+    asyncs <- mapM (\s -> run $ s >>>> sinkIO cb) ss+    (_, r) <- waitAny asyncs+    return r +-- | This is `sources` specialised to `()`.+sources_ :: Transport t => [Source () t o] -> Source () t o+sources_ = sources+ -- ** Sinks  -- | Consume all items with no additional effects. --  -- TODO: Decide if we should use some kind of `nf` evaluation here to force items. -- --- >>> runWaitChan $ pure 1 >>> process print >>> sink+-- >>> runWaitChan $ pure 1 >>> process print >>> sink_ -- 1 -- -sink :: Transport t => Churro t b Void-sink = sinkIO (const (return ()))+sink_ :: Transport t => Churro () t i Void+sink_ = sinkIO (const (return ())) +-- | Consume all items and combines them into a result via their monoid.+-- +-- >>> :set -XFlexibleContexts+-- >>> r <- runWaitChan $ pure' [1 :: Int] >>> sink+-- >>> print r+-- [1]+sink :: (Transport t, Monoid a) => Churro a t a Void+sink = sinkIO return+ -- | Consume a churro with an IO process. --  -- >>> runWaitChan $ pure 1 >>> sinkIO (\x -> print "hello" >> print (succ x)) -- "hello" -- 2-sinkIO :: Transport t => (o -> IO ()) -> Churro t o Void+sinkIO :: (Transport t, Monoid a) => (o -> IO a) -> Churro a t o Void sinkIO cb = buildChurro \i _o -> yankAll i cb +-- | Create a "sink" with more flexibility about when items are demanded using a higher-order "HO" callback.+-- +-- This also allows a non-unit async action that can be recovered when run.+-- +-- WARNING: You should use the provided callback if you want to acually create a sink.+-- +-- TODO: Use hidden callback return type in order to ensure that the callback is called.+-- +-- >>> import System.Timeout (timeout)+-- >>> :{+-- do+--   r <- timeout 100000 $ runWaitChan $ sourceSingleton 1 >>>> sinkHO \ya -> do+--     ya (print . show)+--     return 25+--   print r+-- :}+-- "1"+-- Just 25+sinkHO :: Transport t => (((i -> IO ()) -> IO ()) -> IO a) -> Churro a t i o+sinkHO cb = buildChurro \i _o -> cb (yankAll i)+ -- | Consume and print each item. Used in many examples, but not much use outside debugging! --  -- >>> runWaitChan $ pure "hi" >>> sinkPrint -- "hi"-sinkPrint :: (Transport t, Show a) => Churro t a Void+sinkPrint :: (Transport t, Show a) => Churro () t a Void sinkPrint = sinkIO print      @@ -162,15 +190,15 @@ -- >>> runWaitChan $ pure "hi" >>> process (\x -> print x >> return (reverse x)) >>> sinkPrint -- "hi" -- "ih"-process :: Transport t => (a -> IO b) -> Churro t a b+process :: Transport t => (a -> IO b) -> Churro () t a b process f = processN (fmap pure . f)  -- | Print each item then pass it on.-processPrint :: (Transport t, Show b) => Churro t b b+processPrint :: (Transport t, Show b) => Churro () t b b processPrint = process \x -> do print x >> return x  -- | Print each item with an additional debugging label.-processDebug :: (Transport t, Show b) => String -> Churro t b b+processDebug :: (Transport t, Show b) => String -> Churro () t b b processDebug d = process \x -> putStrLn ("Debugging [" <> d <> "]: " <> show x) >> return x  -- | Process each item with an IO action and potentially yield many items as a result.@@ -180,7 +208,7 @@ -- "1" -- 1 -- 2-processN :: Transport t => (a -> IO [b]) -> Churro t a b+processN :: Transport t => (i -> IO [o]) -> Churro () t i o processN f =     buildChurro \i o -> do         yankAll i \x -> do mapM_ (yeet o . Just) =<< f x@@ -191,7 +219,7 @@ -- >>> runWaitChan $ sourceList [Just 1, Nothing, Just 3] >>> justs >>> sinkPrint -- 1 -- 3-justs :: Transport t => Churro t (Maybe a) a+justs :: Transport t => Churro () t (Maybe a) a justs = mapN (maybe [] pure)  -- | Extract ls from (Left l)s.@@ -199,14 +227,14 @@ -- >>> runWaitChan $ sourceList [Left 1, Right 2, Left 3] >>> lefts >>> sinkPrint -- 1 -- 3-lefts :: Transport t => Churro t (Either a b) a+lefts :: Transport t => Churro () t (Either a b) a lefts = mapN (either pure (const []))  -- | Extract rs from (Right r)s. --  -- >>> runWaitChan $ sourceList [Left 1, Right 2, Left 3] >>> rights >>> sinkPrint -- 2-rights :: Transport t => Churro t (Either a b) b+rights :: Transport t => Churro () t (Either a b) b rights = mapN (either (const []) pure)  -- | Take and yield the first n items.@@ -221,7 +249,7 @@ -- This implementation explicitly stops propagating when the Churro completes, -- although this could be handled by downstream consumer composition terminating -- the producer and just using replicateM.-takeC :: (Transport t, Integral n) => n -> Churro t a a+takeC :: (Transport t, Integral n) => n -> Churro () t a a takeC n = buildChurro \i o -> go n i o     where     go t i o@@ -236,7 +264,7 @@ -- >>> runWaitChan $ sourceList [1..4] >>> dropC 2 >>> sinkPrint -- 3 -- 4-dropC :: (Transport t, Integral n) => n -> Churro t a a+dropC :: (Transport t, Integral n) => n -> Churro () t a a dropC n = buildChurro \i o -> do     replicateM_ (fromIntegral n) (yank i) -- TODO: Check the async behaviour of this...     c2c id i o@@ -246,7 +274,7 @@ -- >>> runWaitChan $ sourceList [1..5] >>> filterC (> 3) >>> sinkPrint -- 4 -- 5-filterC :: Transport t => (a -> Bool) -> Churro t a a+filterC :: Transport t => (a -> Bool) -> Churro () t a a filterC p = mapN (filter p . pure)  -- | Run a pure function over items, producing multiple outputs.@@ -254,7 +282,7 @@ -- >>> runWaitChan $ pure 9 >>> mapN (\x -> [x,x*10]) >>> sinkPrint -- 9 -- 90-mapN :: Transport t => (a -> [b]) -> Churro t a b+mapN :: Transport t => (a -> [b]) -> Churro () t a b mapN f = processN (return . f)  -- | Delay items from being sent downstream.@@ -268,11 +296,11 @@ --  -- >>> runWaitChan $ sourceList [1..2] >>> delay 0.1 >>> sinkTimeCheck -- True-delay :: Transport t => NominalDiffTime -> Churro t a a+delay :: Transport t => NominalDiffTime -> Churro () t a a delay = delayMicro . ceiling @Double . fromRational . (*1000000) . toRational  -- | Delay items in microseconds. Works the same way as `delay`.-delayMicro :: Transport t => Int -> Churro t a a+delayMicro :: Transport t => Int -> Churro () t a a delayMicro d = process \x -> do     threadDelay d     return x@@ -282,7 +310,7 @@ -- >>> runWaitChan $ sourceList [1,2,3] >>> withPrevious >>> sinkPrint -- (1,2) -- (2,3)-withPrevious :: Transport t => Churro t a (a,a)+withPrevious :: Transport t => Churro () t a (a,a) withPrevious = buildChurro \i o -> do     prog Nothing i o      yeet o Nothing@@ -323,12 +351,12 @@ -- "GT" -- 2 -- -processRetry :: Transport t => Natural -> (i -> IO o) -> Churro t i o+processRetry :: Transport t => Natural -> (i -> IO o) -> Churro () t i o processRetry retries f = processRetry' @SomeException retries f >>> rights  -- | Raw version of `processRetry`. -- Polymorphic over exception type and forwards errors. --   -processRetry' :: (Exception e, Transport t) => Natural -> (i -> IO o) -> Churro t i (Either e o)+processRetry' :: (Exception e, Transport t) => Natural -> (i -> IO o) -> Churro () t i (Either e o) processRetry' retries f = arr (0,) >>> processRetry'' retries f  -- | Rawest version of `processRetry`.@@ -336,7 +364,7 @@ --  --   Also polymorphic over exception type. And forwards errors. --   -processRetry'' :: (Transport t, Exception e, Ord n, Enum n) => n -> (a -> IO b) -> Churro t (n, a) (Either e b)+processRetry'' :: (Transport t, Exception e, Ord n, Enum n) => n -> (a -> IO b) -> Churro () t (n, a) (Either e b) processRetry'' retries f =     buildChurro' \i' o i -> do         yankAll o \(n, y) -> do
src/Control/Churro/Transport/Chan.hs view
@@ -21,14 +21,14 @@         c <- newChan         return (ChanIn c, ChanOut c) -type ChurroChan = Churro Chan+type ChurroChan a = Churro a Chan  -- | Convenience function for running a Churro with a Chan Transport. -- -runWaitChan :: ChurroChan Void Void -> IO ()+runWaitChan :: ChurroChan a Void Void -> IO a runWaitChan = runWait  -- | Convenience function for running a Churro into a List with a Chan Transport. -- -runWaitListChan :: ChurroChan Void o -> IO [o]+runWaitListChan :: ChurroChan () Void o -> IO [o] runWaitListChan = runWaitList
src/Control/Churro/Transport/Unagi.hs view
@@ -22,14 +22,14 @@         (i, o) <- newChan         return (ChanIn i, ChanOut o) -type ChurroUnagi = Churro Unagi+type ChurroUnagi a = Churro a Unagi  -- | Convenience function for running a Churro with an Unagi Transport. -- -runWaitUnagi :: ChurroUnagi Void Void -> IO ()+runWaitUnagi :: ChurroUnagi a Void Void -> IO a runWaitUnagi = runWait  -- | Convenience function for running a Churro into a List with an Unagi Transport. -- -runWaitListUnagi :: ChurroUnagi Void o -> IO [o]+runWaitListUnagi :: ChurroUnagi () Void o -> IO [o] runWaitListUnagi = runWaitList
src/Control/Churro/Transport/Unagi/Bounded.hs view
@@ -36,16 +36,16 @@         (i, o) <- newChan (fromIntegral (natVal (Proxy :: Proxy n)))         return (ChanIn i, ChanOut o) -type ChurroUnagiBounded n = Churro (UnagiBounded n)+type ChurroUnagiBounded a n = Churro a (UnagiBounded n)  -- | Convenience function for running a Churro with a Bounded Unagi-Chan Transport. -- -runWaitUnagi :: KnownNat n => ChurroUnagiBounded n Void Void -> IO ()+runWaitUnagi :: KnownNat n => ChurroUnagiBounded a n Void Void -> IO a runWaitUnagi = runWait  -- | Convenience function for running a Churro into a List with a Bounded Unagi-Chan Transport. --  -- >>> runWaitListUnagi @10 $ sourceList [1,2,3] >>> arr succ -- [2,3,4]-runWaitListUnagi :: KnownNat n => ChurroUnagiBounded n Void o -> IO [o]+runWaitListUnagi :: KnownNat n => ChurroUnagiBounded () n Void o -> IO [o] runWaitListUnagi = runWaitList
src/Control/Churro/Types.hs view
@@ -2,6 +2,7 @@ {-# LANGUAGE InstanceSigs #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE BlockArguments #-}+{-# LANGUAGE NoMonomorphismRestriction #-}  -- | Datatypes and definitions used by Churro library. -- @@ -39,10 +40,10 @@ -- Convenience types of `Source`, `Sink`, and `DoubleDipped` are also defined, -- although use is not required. -- -data Churro t i o   = Churro { runChurro :: IO (In t (Maybe i), Out t (Maybe o), Async ()) }-type Source t   o   = Churro t Void o-type Sink   t i     = Churro t i Void-type DoubleDipped t = Churro t Void Void+data Churro a t i o   = Churro { runChurro :: IO (In t (Maybe i), Out t (Maybe o), Async a) }+type Source a t   o   = Churro a t Void o+type Sink   a t i     = Churro a t i Void+type DoubleDipped a t = Churro a t Void Void  -- | The transport method is abstracted via the Transport class -- @@ -80,7 +81,7 @@ -- >>> runWaitChan $ fmap succ s >>> sinkPrint -- 2 -- 3-instance Transport t => Functor (Churro t i) where+instance Transport t => Functor (Churro a t i) where     fmap f c = Churro do         (i,o,a) <- runChurro c         (i',o') <- flex@@ -99,30 +100,38 @@ --  -- >>> runWaitChan $ pure 1 >>> id >>> id >>> id >>> sinkPrint -- 1-instance Transport t => Category (Churro t) where+instance (Transport t, Monoid a) => Category (Churro a t) where     id = Churro do         (i,o) <- flex-        a     <- async (return ())+        a     <- async mempty         return (i,o,a) -    g . f = Churro do-        (fi, fo, fa) <- runChurro f-        (gi, go, ga) <- runChurro g-        a <- async do c2c id fo gi-        b <- async do-            finally' (cancel a >> cancel fa >> cancel ga) do-                wait ga-                cancel fa-                cancel a-        return (fi, go, b)+    g . f = f >>>> g +-- | Category style composition that allows for return type to change downstream.+-- +(>>>>) :: (Transport t, fo ~ gi) => Churro a1 t fi fo -> Churro a2 t gi go -> Churro a2 t fi go+f >>>> g = Churro do+    (fi, fo, fa) <- runChurro f+    (gi, go, ga) <- runChurro g+    a <- async do c2c id fo gi+    b <- async do+        finally' (cancel a >> cancel fa >> cancel ga) do+            r <- wait ga+            cancel fa+            cancel a+            return r+    return (fi, go, b)+ -- | The Applicative instance allows for pairwise composition of Churro pipelines. --   Once again this is covariat and the composition occurs on the output transports of the Churros. --  --  The `pure` method allows for the creation of a Churro yielding a single item. -- -instance Transport t => Applicative (Churro t Void) where-    pure x = buildChurro \_i o -> yeet o (Just x) >> yeet o Nothing+-- TODO: Generalise () to a Monoid constraint.+-- +instance Transport t => Applicative (Churro () t Void) where+    pure = pure'      f <*> g = buildChurro \_i o -> do         (_fi, fo, fa) <- runChurro f@@ -143,10 +152,14 @@         wait fa         wait ga +-- | More general variant of `pure` with Monoid constraint.+pure' :: (Transport t, Monoid a) => o -> Churro a t i o+pure' x = buildChurro \_i o -> yeet o (Just x) >> yeet o Nothing >> return mempty+ -- | The Arrow instance allows for building non-cyclic directed graphs of churros. --  --  The `arr` method allows for the creation of a that maps items with a pure function.---  This is equivalent to `fmap f id`.+--  This is equivalent to `fmap f id`. This is more general and exposed via arr`. --  -- >>> :set -XArrows -- >>> :{@@ -175,8 +188,8 @@ --  -- >>> runWaitChan $ pure 1 >>> (arr show &&& arr succ) >>> sinkPrint -- ("1",2)-instance Transport t => Arrow (Churro t) where-    arr = flip fmap id+instance Transport t => Arrow (Churro () t) where+    arr = arr'      first c = Churro do         (i,o,a)   <- runChurro c@@ -201,24 +214,26 @@          return (ai',bo',a') +-- | More general version of `arr`.+-- +-- Useful when building pipelines that need to work with return types.+arr' :: (Functor (cat a), Category cat) => (a -> b) -> cat a b+arr' f = fmap f id+ -- ** Helpers  -- | A helper to facilitate constructing a Churro that makes new input and output transports available for manipulation. --  -- The manipulations performed are carried out in the async action associated with the Churro -- -buildChurro :: Transport t => (Out t (Maybe i) -> In t (Maybe o) -> IO ()) -> Churro t i o-buildChurro cb = Churro do-    (ai,ao) <- flex-    (bi,bo) <- flex-    a       <- async do cb ao bi-    return (ai,bo,a)+buildChurro :: Transport t => (Out t (Maybe i) -> In t (Maybe o) -> IO a) -> Churro a t i o+buildChurro cb = buildChurro' \_o' i o -> cb i o  -- | A version of `buildChurro` that also passes the original input to the callback so that you can reschedule items. --  -- Used by "retry" style functions. -- -buildChurro' :: Transport t => (In t (Maybe i) -> Out t (Maybe i) -> In t (Maybe o) -> IO ()) -> Churro t i o+buildChurro' :: Transport t => (In t (Maybe i) -> Out t (Maybe i) -> In t (Maybe o) -> IO a) -> Churro a t i o buildChurro' cb = Churro do     (ai,ao) <- flex     (bi,bo) <- flex@@ -235,29 +250,26 @@ --   Won't terminate until the transport has been consumed. --  yankList :: Transport t => Out t (Maybe a) -> IO [a]-yankList t = do-    x <- yank t-    case x of -        Nothing -> return []-        Just y  -> (y :) <$> yankList t+yankList = flip yankAll (pure . pure)  -- | Yank each item from a transport into a callback. -- -yankAll :: Transport t => Out t (Maybe i) -> (i -> IO a) -> IO ()+yankAll :: (Transport t, Monoid a) => Out t (Maybe i) -> (i -> IO a) -> IO a yankAll c f = do     x <- yank c     case x of-        Nothing -> return ()-        Just y  -> f y >> yankAll c f+        Nothing -> mempty+        Just y  -> f y <> yankAll c f  -- | Yank each raw item from a transport into a callback. --  -- The items are wrapped in Maybes and when all items are yanked, Nothing is fed to the callback. -- -yankAll' :: Transport t => Out t (Maybe a) -> (Maybe a -> IO b) -> IO b+yankAll' :: (Transport t, Monoid b) => Out t (Maybe a) -> (Maybe a -> IO b) -> IO b yankAll' c f = do-    yankAll c (f . Just)-    f Nothing+    x <- yankAll c (f . Just)+    y <- f Nothing+    return (x <> y)  -- | Yank then Yeet each item from one Transport into another. -- 
test/Churro/Test/Examples.hs view
@@ -35,7 +35,7 @@ -- Debugging [r2]: 1 -- 1  ---linear :: Transport t => Churro t Void Void+linear :: Transport t => Churro () t Void Void linear = sourceList [1::Int]     >>> ((processDebug "l1" >>> processDebug "l2") >>> processDebug "r1" >>> processDebug "r2")     >>> sinkPrint@@ -45,7 +45,7 @@ -- >>> runWaitChan pipeline -- (fromList [(0,0),(1,1)],fromList [(1,1),(2,2)]) -- (fromList [(1,1),(2,2)],fromList [(2,2),(3,3)])-pipeline :: ChurroChan Void Void+pipeline :: ChurroChan () Void Void pipeline = sourceList (take 3 maps)         >>> withPrevious         >>> takeC (10 :: Int)@@ -58,7 +58,7 @@ --  -- This can fail in the following scenarios if cancellation isn't implemented correctly: -- --- >>> timeout 1500000 $ runWaitChan $ sourceList [1..5] >>> delay 1 >>> takeC 1 >>> sinkPrint+-- >>> timeout 150000 $ runWaitChan $ sourceList [1..5] >>> delay 0.1 >>> takeC 1 >>> sinkPrint -- 1 -- Just () -- @@ -70,7 +70,7 @@ --  -- Cancells upstream infinite producer with no inbuilt delay: -- --- >>> timeout 2500000 $ runWaitChan $ sourceList [1..] >>> delay 1 >>> takeC 1 >>> sinkPrint+-- >>> timeout 2500000 $ runWaitChan $ sourceList [1..] >>> delay 0.1 >>> takeC 1 >>> sinkPrint -- 1 -- Just () -- 
test/Churro/Test/Main.hs view
@@ -1,12 +1,9 @@  module Main where -import Test.DocTest---- import qualified Churro.Test.Examples as Ex--- import qualified Build_doctests       as DT+import Test.DocTest ( doctest ) --- TODO: Find out how to use a different test manager to allow these to be run independently+-- TODO: Pass additional paths in automatically or via arguments. main :: IO () main = do     doctest