-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | boxes -- -- concurrent, effectful boxes @package box @version 0.5.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 -- | Do nothing with values that are committed. -- -- This is useful for keeping the commit end of a box or pipeline open. drain :: Applicative m => Committer m a -- | This is a contramapMaybe, if such a thing existed, as the -- contravariant version of a mapMaybe. See witherable mapC :: Monad m => (b -> m (Maybe a)) -> Committer m a -> Committer m b -- | adds a monadic action to the committer premapC :: Applicative m => (Committer m a -> m ()) -> Committer m a -> Committer m a -- | adds a post-commit monadic action to the committer postmapC :: Monad m => (Committer m a -> m ()) -> Committer m a -> Committer m a -- | commit to a StateT list stateC :: Monad m => Committer (StateT [a] m) a -- | list committer listC :: Monad m => Committer m a -> Committer m [a] instance Control.Monad.Morph.MFunctor Box.Committer.Committer 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 -- | finally run a continuation runCont :: Cont m (m r) -> m r -- | fmap over a continuation and then run the result. -- -- The . position is towards the continuation (<$.>) :: (a -> m r) -> Cont m a -> m r infixr 3 <$.> -- | fmap over a continuation and then run the result. -- -- The . position is towards the continuation (<*.>) :: Cont m (a -> m r) -> Cont m a -> m r infixr 3 <*.> -- | 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 () -- | finally run a Cont_ runCont_ :: Cont_ m (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) -- | like a monadic mapMaybe. (See witherable) mapE :: Monad m => (a -> m (Maybe b)) -> Emitter m a -> Emitter m b -- | read parse emitter, returning the original string on error readE :: (Functor m, Read a) => Emitter m Text -> Emitter m (Either Text a) -- | no error-reporting reading readE_ :: (Monad m, Read a) => Emitter m Text -> Emitter m a -- | parse emitter which returns the original text on failure parseE :: Functor m => Parser a -> Emitter m Text -> Emitter m (Either Text a) -- | no error-reporting parsing parseE_ :: Monad m => Parser a -> Emitter m Text -> Emitter m a -- | adds a pre-emit monadic action to the emitter premapE :: Applicative m => (Emitter m a -> m ()) -> Emitter m a -> Emitter m a -- | adds a post-emit monadic action to the emitter postmapE :: Monad m => (Emitter m a -> m ()) -> Emitter m a -> Emitter m a -- | add a post-emit monadic action on the emitted value (if there was any) postmapM :: Monad m => (a -> m ()) -> Emitter m a -> Emitter m a -- | turn an emitter into a list toListE :: Monad m => Emitter m a -> m [a] -- | convert a list emitter to a Stateful element emitter unlistE :: Monad m => Emitter m [a] -> Emitter (StateT [a] m) a -- | emit from a StateT list -- -- This compiles but is an infinite "a" emitter: -- -- let e1 = hoist (flip evalStateT ["a", "b"::Text]) stateE :: Emitter IO -- Text stateE :: Monad m => Emitter (StateT [a] m) a instance Control.Monad.Morph.MFunctor Box.Emitter.Emitter 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 -- | a profunctor dimapMaybe bmap :: Monad m => (a' -> m (Maybe a)) -> (b -> m (Maybe b')) -> Box m a b -> Box m a' b' -- | Wrong signature for the MFunctor class hoistb :: Monad m => (forall a. m a -> n a) -> Box m c e -> Box n c e -- | Connect an emitter directly to a committer of the same type. -- -- The monadic action returns when the committer finishes. glue :: Monad m => Committer m a -> Emitter m a -> m () -- | Short-circuit a homophonuos box. glueb :: Monad m => Box m a a -> m () -- | fuse a box -- --
-- fuse (pure . pure) == glueb == etc () (Transducer id) --fuse :: Monad m => (a -> m (Maybe b)) -> Box m b a -> m () -- | composition of monadic boxes dotb :: Monad m => Box m a b -> Box m b c -> m (Box m a c) 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, returning the emitter result queueC :: MonadConc m => (Committer m a -> m l) -> (Emitter m a -> m r) -> m l -- | create an unbounded queue, returning the emitter result queueE :: 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. withQE :: MonadConc m => Queue a -> (Queue a -> m (Box m a a, m ())) -> (Committer m a -> m l) -> (Emitter m a -> m r) -> m r -- | connect a committer and emitter action via spawning a queue, and wait -- for both to complete. withQC :: MonadConc m => Queue a -> (Queue a -> m (Box m a a, m ())) -> (Committer m a -> m l) -> (Emitter 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 ()) -- | turn a queue into a box (and a seal), and lift from stm to the -- underlying monad. toBoxM :: MonadConc m => Queue a -> m (Box m a a, m ()) -- | lift a box from STM liftB :: MonadConc m => Box (STM m) a b -> Box m a b -- | 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 -- | turn a box action into a box continuation fromAction :: MonadConc m => (Box m a b -> m r) -> Cont m (Box m b a) -- | connect up two box actions via two queues fuseActions :: MonadConc m => (Box m a b -> m r) -> (Box m b a -> m r') -> m r' -- | various ways to connect things up module Box.Connectors -- | Turn a list into an Emitter continuation via a Queue fromListE :: MonadConc m => [a] -> Cont m (Emitter m a) -- | fromList_ directly supplies to a committer action -- -- FIXME: fromList_ combined with cRef is failing dejavu concurrency -- testing... fromList_ :: Monad m => [a] -> Committer m a -> m () -- | toList_ directly receives from an emitter -- -- TODO: check isomorphism -- --
-- toList_ == toListE --toList_ :: Monad m => Emitter m a -> m [a] -- | take a list, emit it through a box, and output the committed result. -- -- The pure nature of this computation is highly useful for testing, -- especially where parts of the box under investigation has -- non-deterministic attributes. fromToList_ :: Monad m => [a] -> (Box (StateT ([b], [a]) m) b a -> StateT ([b], [a]) m r) -> m [b] -- | hook a committer action to a queue, creating an emitter continuation emitQ :: MonadConc m => (Committer m a -> m r) -> Cont m (Emitter m a) -- | hook a committer action to a queue, creating an emitter continuation commitQ :: MonadConc m => (Emitter m a -> m r) -> Cont m (Committer m a) -- | finite sink sink :: MonadConc m => Int -> (a -> m ()) -> Cont m (Committer m a) -- | finite source source :: MonadConc m => Int -> m a -> Cont m (Emitter m a) -- | glues an emitter to a committer, then resupplies the 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) -- | fuse a committer to a buffer queueCommitter :: MonadConc m => Committer m a -> Cont m (Committer m a) -- | fuse an emitter to a buffer queueEmitter :: MonadConc m => Emitter m a -> Cont m (Emitter m a) -- | concurrently run two emitters -- -- This differs from mappend in that the monoidal (and alternative) -- instance of an Emitter is left-biased (The left emitter exhausts -- before the right one is begun). This is non-deterministically -- concurrent. concurrentE :: MonadConc m => Emitter m a -> Emitter m a -> Cont m (Emitter m a) -- | run two committers concurrently concurrentC :: MonadConc m => Committer m a -> Committer m a -> Cont m (Committer m a) -- | IO actions module Box.IO -- | emit Text from stdin inputs -- --
-- >>> :t emit fromStdin -- emit fromStdin :: IO (Maybe Text) --fromStdin :: Emitter IO Text -- | commit to stdout -- --
-- >>> commit toStdout ("I'm committed!" :: Text)
-- I'm committed!
-- True
--
toStdout :: Committer IO Text
-- | finite console emitter
fromStdinN :: Int -> Cont IO (Emitter IO Text)
-- | finite console committer
toStdoutN :: Int -> Cont IO (Committer IO Text)
-- | read from console, throwing away read errors
readStdin :: Read a => Emitter IO a
-- | show to stdout
showStdout :: Show a => Committer IO a
-- | Emits lines of Text from a handle.
handleE :: Handle -> Emitter IO Text
-- | Commit lines of Text to a handle.
handleC :: Handle -> Committer IO Text
-- | commit to a list IORef
cRef :: MonadConc m => m (Committer m a, m [a])
-- | emit from a list IORef
eRef :: MonadConc m => [a] -> m (Emitter m a)
-- | Emits lines of Text from a file.
fileE :: FilePath -> Cont IO (Emitter IO Text)
-- | Commits lines of Text to a file.
fileWriteC :: FilePath -> Cont IO (Committer IO Text)
-- | Commits lines of Text, appending to a file.
fileAppendC :: FilePath -> Cont IO (Committer IO Text)
-- | timing effects
module Box.Time
-- | sleep for x seconds
sleep :: MonadConc m => Double -> m ()
-- | sleep until a certain time (in the future)
sleepUntil :: UTCTime -> IO ()
-- | A value with a UTCTime annotation.
data Stamped a
Stamped :: UTCTime -> a -> Stamped a
[stamp] :: Stamped a -> UTCTime
[value] :: Stamped a -> a
-- | Add the current time
stampNow :: (MonadConc m, MonadIO m) => a -> m (Stamped a)
-- | adding a time stamp
stampE :: (MonadConc m, MonadIO m) => Emitter m a -> Emitter m (Stamped a)
-- | wait until Stamped time before emitting
emitOn :: Emitter IO (Stamped a) -> Emitter IO a
-- | reset the emitter stamps to by in sync with the current time and
-- adjust the speed >>> let e1 = fromListE (zipWith (x a ->
-- Stamped (addUTCTime (fromDouble x) t) a) [0..5] [0..5])
playback :: Double -> Emitter IO (Stamped a) -> IO (Emitter IO (Stamped a))
-- | simulate a delay from a (Stamped a) Emitter relative to the first
-- timestamp
simulate :: Double -> Emitter IO (Stamped a) -> Cont IO (Emitter IO 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 :: Monad m => s -> Transducer s a b -> Box m b a -> m s
-- | create an committer from a stream continuation
toCommitter :: MonadConc m => (Stream (Of a) m () -> m r) -> Cont m (Committer m a)
-- | create an emitter from a stream
toEmitter :: MonadConc m => Stream (Of b) m () -> Cont m (Emitter m b)
-- | turn an emitter into a stream
toStream :: Monad m => Emitter m a -> Stream (Of a) m ()
-- | turn a stream into a committer
fromStream :: Monad m => Stream (Of b) m () -> Committer m b -> m ()
-- | create a committer from a fold
foldCommitter :: MonadConc m => FoldM m a () -> Cont m (Committer m a)
-- | create a committer from a sink
sinkCommitter :: MonadConc m => (a -> m ()) -> Cont m (Committer m a)
instance Control.Category.Category (Box.Transducer.Transducer s)
-- | Effectful, profunctor boxes designed for concurrency.
--
-- This library follows the ideas and code from pipes-concurrency
-- and mvc but with some polymorphic tweaks and definitively more
-- pretentious names.
module Box