-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | boxes -- -- concurrent, effectful boxes @package box @version 0.0.1.5 -- | commit module Box.Committer -- | a Committer a "commits" values of type a. A Sink and a Consumer are -- some other metaphors for this. -- -- A Committer absorbs the value being committed; the value -- disappears into the opaque thing that is a Committer from the pov of -- usage. newtype Committer m a Committer :: (a -> m Bool) -> Committer m a [commit] :: Committer m a -> a -> m Bool -- | lift a committer from STM liftC :: MonadConc m => Committer (STM m) a -> Committer m a -- | This is a contramapMaybe, if such a thing existed, as the -- contravariant version of a mapMaybe. See witherable cmap :: Monad m => (b -> m (Maybe a)) -> Committer m a -> Committer m b -- | prism handler handles :: Monad m => ((b -> Constant (First b) b) -> a -> Constant (First b) a) -> Committer m b -> Committer m a instance GHC.Base.Applicative m => GHC.Base.Semigroup (Box.Committer.Committer m a) instance GHC.Base.Applicative m => GHC.Base.Monoid (Box.Committer.Committer m a) instance Data.Functor.Contravariant.Contravariant (Box.Committer.Committer m) instance GHC.Base.Applicative m => Data.Functor.Contravariant.Divisible.Divisible (Box.Committer.Committer m) instance GHC.Base.Applicative m => Data.Functor.Contravariant.Divisible.Decidable (Box.Committer.Committer m) module Box.Cont -- | A continuation similar to ContT but where the result type is -- swallowed by an existential newtype Cont m a Cont :: (forall r. (a -> m r) -> m r) -> Cont m a [with] :: Cont m a -> forall r. (a -> m r) -> m r -- | sometimes you have no choice but to void it up newtype Cont_ m a Cont_ :: ((a -> m ()) -> m ()) -> Cont_ m a [with_] :: Cont_ m a -> (a -> m ()) -> m () instance GHC.Base.Functor (Box.Cont.Cont_ m) instance GHC.Base.Applicative (Box.Cont.Cont_ m) instance GHC.Base.Monad (Box.Cont.Cont_ m) instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (Box.Cont.Cont_ m) instance GHC.Base.Semigroup a => GHC.Base.Semigroup (Box.Cont.Cont_ m a) instance (GHC.Base.Functor m, GHC.Base.Semigroup a, GHC.Base.Monoid a) => GHC.Base.Monoid (Box.Cont.Cont_ m a) instance GHC.Base.Functor (Box.Cont.Cont m) instance GHC.Base.Applicative (Box.Cont.Cont m) instance GHC.Base.Monad (Box.Cont.Cont m) instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (Box.Cont.Cont m) instance GHC.Base.Semigroup a => GHC.Base.Semigroup (Box.Cont.Cont m a) instance (GHC.Base.Functor m, GHC.Base.Semigroup a, GHC.Base.Monoid a) => GHC.Base.Monoid (Box.Cont.Cont m a) -- | emit module Box.Emitter -- | an Emitter "emits" values of type a. A Source & a Producer -- (of as) are the two other alternative but overloaded -- metaphors out there. -- -- An Emitter 'reaches into itself' for the value to emit, where itself -- is an opaque thing from the pov of usage. An Emitter is named for its -- main action: it emits. newtype Emitter m a Emitter :: m (Maybe a) -> Emitter m a [emit] :: Emitter m a -> m (Maybe a) liftE :: MonadConc m => Emitter (STM m) a -> Emitter m a -- | like a monadic mapMaybe. (See witherable) emap :: Monad m => (a -> m (Maybe b)) -> Emitter m a -> Emitter m b -- | prism handler keeps :: Monad m => ((b -> Constant (First b) b) -> a -> Constant (First b) a) -> Emitter m a -> Emitter m b -- | read parse emitter eRead :: (Functor m, Read a) => Emitter m Text -> Emitter m (Either Text a) -- | attoparsec parse emitter eParse :: Functor m => Parser a -> Emitter m Text -> Emitter m (Either Text a) instance GHC.Base.Functor m => GHC.Base.Functor (Box.Emitter.Emitter m) instance GHC.Base.Applicative m => GHC.Base.Applicative (Box.Emitter.Emitter m) instance GHC.Base.Monad m => GHC.Base.Monad (Box.Emitter.Emitter m) instance (GHC.Base.Monad m, GHC.Base.Alternative m) => GHC.Base.Alternative (Box.Emitter.Emitter m) instance (GHC.Base.Alternative m, GHC.Base.Monad m) => GHC.Base.MonadPlus (Box.Emitter.Emitter m) instance (GHC.Base.Alternative m, GHC.Base.Monad m) => GHC.Base.Semigroup (Box.Emitter.Emitter m a) instance (GHC.Base.Alternative m, GHC.Base.Monad m) => GHC.Base.Monoid (Box.Emitter.Emitter m a) -- | A box is something that commits and emits module Box.Box -- | A Box is a product of a Committer m and an Emitter. Think of a box -- with an incoming wire and an outgoing wire. Now notice that the -- abstraction is reversable: are you looking at two wires from "inside a -- box"; a blind erlang grunt communicating with the outside world via -- the two thin wires, or are you looking from "outside the box"; -- interacting with a black box object. Either way, it's a box. And -- either way, the committer is contravariant and the emitter covariant -- so it forms a profunctor. -- -- a Box can also be seen as having an input tape and output tape, thus -- available for turing and finite-state machine metaphorics. data Box m c e Box :: Committer m c -> Emitter m e -> Box m c e [committer] :: Box m c e -> Committer m c [emitter] :: Box m c e -> Emitter m e -- | lift a box from STM liftB :: MonadConc m => Box (STM m) a b -> Box m a b -- | a profunctor dimapMaybe bmap :: Monad m => (a' -> m (Maybe a)) -> (b -> m (Maybe b')) -> Box m a b -> Box m a' b' instance GHC.Base.Functor m => Data.Profunctor.Unsafe.Profunctor (Box.Box.Box m) instance (GHC.Base.Alternative m, GHC.Base.Monad m) => GHC.Base.Semigroup (Box.Box.Box m c e) instance (GHC.Base.Alternative m, GHC.Base.Monad m) => GHC.Base.Monoid (Box.Box.Box m c e) -- | queues Follows pipes-concurrency module Box.Queue -- | Queue specifies how messages are queued data Queue a Unbounded :: Queue a Bounded :: Int -> Queue a Single :: Queue a Latest :: a -> Queue a Newest :: Int -> Queue a New :: Queue a -- | create an unbounded queue queue :: MonadConc m => (Committer (STM m) a -> m l) -> (Emitter (STM m) a -> m r) -> m (l, r) -- | create an unbounded queue, returning the committer result queueC :: MonadConc m => (Committer (STM m) a -> m l) -> (Emitter (STM m) a -> m r) -> m l -- | create an unbounded queue, returning the emitter result queueE :: MonadConc m => (Committer (STM m) a -> m l) -> (Emitter (STM m) a -> m r) -> m r -- | create an unbounded queue, returning the emitter result queueCM :: MonadConc m => (Committer m a -> m l) -> (Emitter m a -> m r) -> m l -- | create an unbounded queue, returning the emitter result queueEM :: MonadConc m => (Committer m a -> m l) -> (Emitter m a -> m r) -> m r -- | create an unbounded queue, returning the committer result queueCLog :: (Show a, MonadConc m, MonadIO m) => (Committer m a -> m l) -> (Emitter m a -> m r) -> m l -- | create an unbounded queue, returning the emitter result queueELog :: (Show a, MonadConc m, MonadIO m) => (Committer m a -> m l) -> (Emitter m a -> m r) -> m r -- | wait for the first action, and then cancel the second waitCancel :: MonadConc m => m b -> m a -> m b toBoxLog :: (Show a, MonadIO m, MonadConc m) => Queue a -> m (Box m a a, m ()) -- | create a queue, returning the ends ends :: MonadSTM stm => Queue a -> stm (a -> stm (), stm a) -- | plugs box continuations module Box.Plugs -- | hook an emitter action to a queue, creating a committer continuation commitPlug :: (Emitter STM a -> IO ()) -> Cont IO (Committer STM a) -- | hook a committer action to a queue, creating an emitter continuation emitPlug :: (Committer STM a -> IO r) -> Cont IO (Emitter STM a) -- | hook a committer action to a queue, creating an emitter continuation emitPlugM :: (Committer IO a -> IO r) -> Cont IO (Emitter IO a) -- | create a double-queued box plug boxPlug :: (Emitter STM a -> IO ()) -> (Committer STM b -> IO ()) -> Cont IO (Box STM a b) -- | create a box plug from a box action. Caution: implicitly, this (has -- to) forget interactions between emitter and committer in the one -- action (and it does so silently). These forgotten interactions are -- typically those that create races boxForgetPlug :: (Box STM b a -> IO ()) -> Cont IO (Box STM a b) -- | various ways to connect things up module Box.Connectors -- | fuse an emitter directly to a committer fuse_ :: Monad m => Emitter m a -> Committer m a -> m () -- | slightly more efficient version fuseSTM_ :: MonadConc m => Emitter (STM m) a -> Committer (STM m) a -> m () -- | fuse a box -- --
--   (fuse (pure . Just) $ liftB <$> (Box <$> cStdout 2 <*> emitter')) >> sleep 1
--   
-- -- hi bye -- --
--   etc () (Transducer id) == fuse (pure . pure) . fmap liftB
--   
fuse :: Monad m => (a -> m (Maybe b)) -> Cont m (Box m b a) -> m () -- | fuse a box with an STM mapMaybe action fuseSTM :: MonadConc m => (a -> STM m (Maybe b)) -> Cont m (Box (STM m) b a) -> m () -- | fuse-branch an emitter forkEmit :: Monad m => Emitter m a -> Committer m a -> Emitter m a -- | a box modifier that feeds commits back to the emitter feedback :: MonadConc m => (a -> m (Maybe b)) -> Cont m (Box m b a) -> Cont m (Box m b a) -- | an emitter post-processor that cons transformed emissions back into -- the emitter feedbackE :: MonadConc m => (a -> m (Maybe a)) -> Emitter m a -> Cont m (Emitter m a) -- | fuse an emitter to a buffer fuseEmit :: MonadConc m => Emitter (STM m) a -> Cont m (Emitter (STM m) a) -- | fuse an emitter to a buffer fuseEmitM :: MonadConc m => Emitter m a -> Cont m (Emitter m a) -- | fuse a committer to a buffer fuseCommit :: MonadConc m => Committer (STM m) a -> Cont m (Committer (STM m) a) -- | merge two emitters -- -- This differs from `liftA2 (<>)` in that the monoidal (and -- alternative) instance of an Emitter is left-biased (The left emitter -- exhausts before the right one is begun). This merge is concurrent. emerge :: MonadConc m => Cont m (Emitter (STM m) a, Emitter (STM m) a) -> Cont m (Emitter (STM m) a) -- | monadic version emergeM :: MonadConc m => Cont m (Emitter m a, Emitter m a) -> Cont m (Emitter m a) -- | merge two committers -- -- not working splitCommit :: MonadConc m => Cont m (Committer (STM m) a) -> Cont m (Either (Committer (STM m) a) (Committer (STM m) a)) -- | a failed attempt to understand the either continuation style contCommit :: Either (Committer m Text) (Committer m Text) -> Committer m Text module Box.Broadcast -- | a broadcaster newtype Broadcaster m a Broadcaster :: TVar m (Committer m a) -> Broadcaster m a [unBroadcast] :: Broadcaster m a -> TVar m (Committer m a) -- | create a (broadcaster, committer) broadcast :: MonadSTM stm => stm (Broadcaster stm a, Committer stm a) -- | subscribe to a broadcaster subscribe :: MonadConc m => Broadcaster (STM m) a -> Cont m (Emitter (STM m) a) -- | a funneler newtype Funneler m a Funneler :: TVar m (Emitter m a) -> Funneler m a [unFunnel] :: Funneler m a -> TVar m (Emitter m a) -- | create a (funneler, emitter) funnel :: MonadSTM stm => stm (Funneler stm a, Emitter stm a) -- | widen to a funneler widen :: MonadConc m => Funneler (STM m) a -> Cont m (Committer (STM m) a) -- | Streaming functionality module Box.Stream -- | turn an emitter into a stream toStream :: MonadConc m => Emitter (STM m) a -> Stream (Of a) m () -- | turn a stream into a committer fromStream :: MonadConc m => Stream (Of b) m () -> Committer (STM m) b -> m () -- | create a committer from a stream consumer toCommit :: MonadConc m => (Stream (Of a) m () -> m r) -> Cont m (Committer (STM m) a) -- | create a committer from a fold toCommitFold :: MonadConc m => FoldM m a () -> Cont m (Committer (STM m) a) -- | create a committer from a sink toCommitSink :: MonadConc m => (a -> m ()) -> Cont m (Committer (STM m) a) -- | create an emitter from a stream toEmit :: MonadConc m => Stream (Of a) m () -> Cont m (Emitter (STM m) a) -- | insert a queue into a stream (left biased collapse) todo: look at -- biases queueStream :: MonadConc m => Stream (Of a) m () -> Cont m (Stream (Of a) m ()) -- | turn an emitter into a stream toStreamM :: MonadConc m => Emitter m a -> Stream (Of a) m () -- | turn a stream into a committer fromStreamM :: MonadConc m => Stream (Of b) m () -> Committer m b -> m () -- | timing effects module Box.Time -- | sleep for x seconds sleep :: MonadConc m => Double -> m () -- | keeping a box open sometimes needs a long running emitter keepOpen :: MonadConc m => Cont m (Emitter (STM m) a) -- | a stream with suggested delays. DiffTime is the length of time to wait -- since the start of the stream > delayTimed (S.each (zip -- (fromIntegral $ [1..10]) [1..10])) |> S.print delayTimed :: (MonadConc m, MonadIO m) => Stream (Of (NominalDiffTime, a)) m () -> Stream (Of a) m () data Stamped a Stamped :: UTCTime -> a -> Stamped a [timestamp] :: Stamped a -> UTCTime [value] :: Stamped a -> a stampNow :: (MonadConc m, MonadIO m) => a -> m (Stamped a) -- | adding a time stamp todo: how to do this properly? emitStamp :: (MonadConc m, MonadIO m) => Cont m (Emitter m a) -> Cont m (Emitter m (Stamped a)) instance GHC.Read.Read a => GHC.Read.Read (Box.Time.Stamped a) instance GHC.Show.Show a => GHC.Show.Show (Box.Time.Stamped a) instance GHC.Classes.Eq a => GHC.Classes.Eq (Box.Time.Stamped a) -- | transduce module Box.Transducer -- | transduction wiki says: "A transducer is a device that converts -- energy from one form to another." Translated to context, this -- Transducer converts a stream of type a to a stream of a different -- type. newtype Transducer s a b Transducer :: (forall m. Monad m => Stream (Of a) (StateT s m) () -> Stream (Of b) (StateT s m) ()) -> Transducer s a b [transduce] :: Transducer s a b -> forall m. Monad m => Stream (Of a) (StateT s m) () -> Stream (Of b) (StateT s m) () -- | emit - transduce - commit -- -- with etc, you're in the box, and inside the box, there are no effects: -- just a stream of as, pure functions and state tracking. It's -- a nice way to code, and very friendly for the compiler. When the -- committing and emitting is done, the box collapses to state. -- -- The combination of an input tape, an output tape, and a state-based -- stream computation lends itself to the etc computation as a -- finite-state transducer or mealy machine. etc :: MonadConc m => s -> Transducer s a b -> Cont m (Box (STM m) b a) -> m s etcM :: (MonadConc m, MonadBase m m) => s -> Transducer s a b -> Cont m (Box m b a) -> m s -- | convert a Pipe to a Transducer asPipe :: Monad m => Pipe a b (StateT s m) () -> Stream (Of a) (StateT s m) () -> Stream (Of b) (StateT s m) () instance Control.Category.Category (Box.Transducer.Transducer s) -- | IO actions module Box.IO -- | a single stdin committer action cStdin_ :: Committer (STM IO) Text -> IO () -- | a finite stdin committer action cStdin :: Int -> Committer (STM IO) Text -> IO () -- | a forever stdin committer action cStdin' :: Committer (STM IO) Text -> IO () -- | a Cont stdin emitter eStdin :: Int -> Cont IO (Emitter (STM IO) Text) -- | read from console, throwing away read errors readStdin :: Read a => Cont IO (Emitter (STM IO) a) -- | a single stdout emitter action eStdout_ :: Print a => Emitter (STM IO) a -> IO () -- | a finite stdout emitter action eStdout :: Print a => Int -> Emitter (STM IO) a -> IO () -- | a finite stdout emitter action eStdoutM :: Print a => Int -> Emitter IO a -> IO () -- | a forever stdout emitter action eStdout' :: Print a => Emitter (STM IO) a -> IO () -- | a Cont stdout committer cStdout :: Print a => Int -> Cont IO (Committer (STM IO) a) -- | show to stdout showStdout :: Show a => Cont IO (Committer (STM IO) a) -- | console box > etc () (Trans $ s -> s & S.takeWhile (/="q") -- & S.map ("echo: " <>)) (console 5) consolePlug :: Int -> Cont IO (Box (STM IO) Text Text) -- | emit lines from a file emitLines :: FilePath -> Cont IO (Emitter (STM IO) Text) -- | commit lines to a file commitLines :: FilePath -> Cont IO (Committer (STM IO) Text) -- | commit to a list CRef cCRef :: MonadConc m => m (IORef m [b], Cont m (Committer (STM m) b), m [b]) -- | commit to a monoidal CRef cCRefM :: (MonadConc m, Monoid a) => m (IORef m a, Cont m (Committer (STM m) a), m a) -- | fold an emitter through a transduction, committing to a list toListM :: MonadConc m => Cont m (Emitter (STM m) a) -> s -> Transducer s a b -> m ([b], s) -- | get all commissions as a list getCommissions :: MonadConc m => Cont m (Emitter (STM m) a) -> s -> Transducer s a b -> m [b] -- | get all emissions getEmissions :: MonadConc m => Int -> Cont m (Emitter (STM m) a) -> m [a] -- | Boxes that emit, transduce & commit -- -- This library follows the ideas and code from pipes-concurrency -- and mvc but with some polymorphic tweaks and definitively more -- pretentious names. module Box module Box.Control data ControlComm Ready :: ControlComm Check :: ControlComm Died :: ControlComm Stop :: ControlComm Kill :: ControlComm ShutDown :: ControlComm Start :: ControlComm Reset :: ControlComm On :: Bool -> ControlComm Log :: Text -> ControlComm type ControlBox m = (MonadConc m) => Cont m (Box (STM m) ControlComm ControlComm) data ControlConfig KeepAlive :: Double -> ControlConfig AllowDeath :: ControlConfig defaultControlConfig :: ControlConfig consoleControlBox :: ControlBox IO parseControlComms :: Parser ControlComm -- | an effect that can be started and stopped committer is an existence -- test controlBox :: (MonadConc m) => ControlConfig -> m () -> -- ControlBox m controlBox :: ControlConfig -> IO a -> Box (STM IO) ControlComm ControlComm -> IO Bool runControlBox :: ControlConfig -> IO () -> IO () -- | send Start, wait for a Ready signal, run action, wait x secs, then -- send Quit testBox :: IO Bool timeOut :: Double -> ControlBox m instance GHC.Classes.Eq Box.Control.ControlConfig instance GHC.Show.Show Box.Control.ControlConfig instance GHC.Generics.Generic Box.Control.ControlComm instance Data.Data.Data Box.Control.ControlComm instance GHC.Classes.Eq Box.Control.ControlComm instance GHC.Read.Read Box.Control.ControlComm instance GHC.Show.Show Box.Control.ControlComm -- | based on -- https://github.com/Gabriel439/Haskell-MVC-Updates-Library module Box.Updater -- | An updater of a value a, where the updating process consists of an IO -- fold over an emitter data Updater a Updater :: FoldM IO e a -> Cont IO (Emitter STM e) -> Updater a -- | Create an Updatable value using a pure Fold updater :: Fold e a -> Cont IO (Emitter STM e) -> Updater a -- | run an action on each update > listen mempty = id > > listen -- (f <> g) = listen g . listen f listen :: (a -> IO ()) -> Updater a -> Updater a updates :: Updater a -> Cont IO (Emitter STM a) instance GHC.Base.Functor Box.Updater.Updater instance GHC.Base.Applicative Box.Updater.Updater