-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | boxes -- -- concurrent, effectful boxes @package box @version 0.3.0 -- | 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) -- | A continuation type. module Box.Cont -- | A continuation similar to ` Control.Monad.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 a's) 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) -- | lift an STM emitter 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 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 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 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 emitter result queueEM' :: MonadConc 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 -- | create a queue, returning the ends ends :: MonadSTM stm => Queue a -> stm (a -> stm (), stm a) -- | connect a committer and emitter action via spawning a queue, and wait -- for both to complete. withQ :: MonadConc m => Queue a -> (Queue a -> STM m (Box (STM m) a a, STM m ())) -> (Committer (STM m) a -> m l) -> (Emitter (STM m) a -> m r) -> m (l, r) -- | connect a committer and emitter action via spawning a queue, and wait -- for emitter to complete. withQE :: MonadConc m => Queue a -> (Queue a -> STM m (Box (STM m) a a, STM m ())) -> (Committer (STM m) a -> m l) -> (Emitter (STM m) a -> m r) -> m r -- | connect a committer and emitter action via spawning a queue, and wait -- for committer to complete. withQC :: MonadConc m => Queue a -> (Queue a -> STM m (Box (STM m) a a, STM m ())) -> (Committer (STM m) a -> m l) -> (Emitter (STM m) a -> m r) -> m l -- | turn a queue into a box (and a seal) toBox :: MonadSTM stm => Queue a -> stm (Box stm a a, stm ()) -- | run two actions concurrently, but wait and return on the left result. concurrentlyLeft :: MonadConc m => m a -> m b -> m a -- | run two actions concurrently, but wait and return on the right result. concurrentlyRight :: MonadConc m => m a -> m b -> m b -- | 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) -- | fuse a committer to a buffer fuseCommitM :: MonadConc m => Committer m a -> Cont m (Committer 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) -- | split a committer splitCommit :: MonadConc m => Cont m (Committer m a) -> Cont m (Either (Committer m a) (Committer m a)) -- | split a committer (STM m) splitCommitSTM :: MonadConc m => Cont m (Committer (STM m) a) -> Cont m (Either (Committer (STM m) a) (Committer (STM m) a)) -- | use a split committer contCommit :: Either (Committer m a) (Committer m b) -> (Committer m a -> Committer m b) -> Committer m b -- | This module is experimental and may not work. 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 () -- | A value with a timestamp annotation. data Stamped a Stamped :: UTCTime -> a -> Stamped a [timestamp] :: Stamped a -> UTCTime [value] :: Stamped a -> a -- | Add the current time 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 a's, 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 -- | Monadic version of etc. 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_ :: Emitter (STM IO) Text -> IO () -- | a finite stdout emitter action eStdout :: Int -> Emitter (STM IO) Text -> IO () -- | a finite stdout emitter action eStdoutM :: Int -> Emitter IO Text -> IO () -- | a forever stdout emitter action eStdout' :: Emitter (STM IO) Text -> IO () -- | a Cont stdout committer cStdout :: Int -> Cont IO (Committer (STM IO) Text) -- | a Cont stdout committer cStdout' :: Cont IO (Committer (STM IO) Text) -- | a Cont stdin emitter eStdin' :: Cont IO (Emitter (STM IO) Text) -- | show to stdout showStdout :: Show a => Cont IO (Committer (STM IO) a) -- | Get lines from a handle forever. getLine :: Handle -> Committer (STM IO) Text -> IO () -- | a forever getLine committer action putLine :: Handle -> Emitter (STM IO) Text -> IO () -- | 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 -- | & is a reverse application operator. This provides -- notational convenience. Its precedence is one higher than that of the -- forward application operator $, which allows & to be -- nested in $. -- --
-- >>> 5 & (+1) & show -- "6" --(&) :: () => a -> (a -> b) -> b infixl 1 & -- | An example of a Box for the command line. module Box.Control -- | request ADT data ControlRequest Check :: ControlRequest Start :: ControlRequest Stop :: ControlRequest Reset :: ControlRequest Quit :: ControlRequest -- | response ADT data ControlResponse ShuttingDown :: ControlResponse Status :: (Toggle, Int) -> ControlResponse Info :: Text -> ControlResponse data Toggle On :: Toggle Off :: Toggle -- | A Box that communicates via ControlRequest and -- ControlResponse or an underlying typed-channel type ControlBox a b m = (MonadConc m) => Cont m (Box (STM m) (Either ControlResponse a) (Either ControlRequest b)) -- | A Box that only communicates via ControlRequest and -- ControlResponse type ControlBox_ m = (MonadConc m) => Cont m (Box (STM m) ControlResponse ControlRequest) data ControlConfig ControlConfig :: Int -> Bool -> Maybe Double -> Bool -> ControlConfig -- | maximum number of starts allowed [starts] :: ControlConfig -> Int -- | whether to start automatically [autoStart] :: ControlConfig -> Bool -- | whether to rerun with a delay if the action dies [autoRestart] :: ControlConfig -> Maybe Double -- | logging debug Info [debug] :: ControlConfig -> Bool -- | Default is one start, manual start and no autorestart. defaultControlConfig :: ControlConfig -- | a command-line control box. consoleControlBox :: ControlBox Text Text IO -- | a command-line control box. consoleControlBox_ :: ControlBox_ IO -- | Parse command line requests parseControlRequest :: Parser a -> Parser (Either ControlRequest a) -- | an effect that can be started, stopped and restarted (a limited number -- of times) controlBox :: ControlConfig -> IO a -> Box (STM IO) ControlResponse ControlRequest -> IO () -- | an effect that can be started, stopped and restarted (a limited number -- of times) controlBoxProcess :: ControlConfig -> ProcessConfig Handle Handle () -> Box (STM IO) (Either ControlResponse Text) (Either ControlRequest Text) -> IO () controlConsole :: Cont IO (Box (STM IO) (Either ControlResponse Text) (Either ControlRequest Text)) -- | manual testing > testBoxManual (ControlConfig 1 True (Just 0.5) -- False) 2.3 (beep 3 1 0.5) Status (On,0) beep 1 beep 2 beep 3 Left -- ShutDown testBoxManual :: ControlConfig -> Double -> IO () -> IO () -- | auto testing FIXME: Doesn't work with doctest > testBoxAuto -- (ControlConfig 5 True (Just 0.2) False) 5 [(Check, 0.1), (Start,0.1), -- (Stop,1), (Start, 0.1), (Check, 0.1), (Reset,0.1)] (beep 2 1 1) Left -- (Status (On,5)) Left (Status (On,4)) Left (Status (On,4)) beep 1 Left -- (Status (Off,4)) Left (Status (On,4)) Left (Status (On,3)) Left -- (Status (On,2)) beep 1 beep 2 beep 1 Left ShuttingDown -- -- testBoxAuto (ControlConfig 1 True (Just 0.5) False) 3 [(Reset,1.1), -- (Quit, 1)] (beep 3 1 1) Left (Status (On,1)) beep 1 Left ShuttingDown -- Left (Status (On,-1)) testBoxAuto :: ControlConfig -> Double -> [(ControlRequest, Double)] -> IO () -> IO () -- | action for testing beep :: Int -> Int -> Double -> IO () -- | A box with a self-destruct timer. timeOut :: Double -> ControlBox m a b -- | a canned ControlRequest emitter with delays timedRequests :: MonadConc m => [(ControlRequest, Double)] -> Cont m (Emitter (STM m) ControlRequest) testCatControl :: ControlConfig -> IO () instance GHC.Classes.Ord Box.Control.ControlConfig instance GHC.Classes.Eq Box.Control.ControlConfig instance GHC.Show.Show Box.Control.ControlConfig instance GHC.Generics.Generic Box.Control.ControlResponse instance GHC.Classes.Eq Box.Control.ControlResponse instance GHC.Read.Read Box.Control.ControlResponse instance GHC.Show.Show Box.Control.ControlResponse instance GHC.Generics.Generic Box.Control.Toggle instance GHC.Classes.Eq Box.Control.Toggle instance GHC.Read.Read Box.Control.Toggle instance GHC.Show.Show Box.Control.Toggle instance GHC.Generics.Generic Box.Control.ControlRequest instance Data.Data.Data Box.Control.ControlRequest instance GHC.Classes.Eq Box.Control.ControlRequest instance GHC.Read.Read Box.Control.ControlRequest instance GHC.Show.Show Box.Control.ControlRequest -- | 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 Updater 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 -- | Convert an Updater to an Emitter continuation. updates :: Updater a -> Cont IO (Emitter STM a) instance GHC.Base.Functor Box.Updater.Updater instance GHC.Base.Applicative Box.Updater.Updater