-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | boxes -- -- A profunctor effect @package box @version 0.8.0 -- | Extra Codensity operators. module Box.Codensity -- | close a continuation -- --
-- >>> close $ glue showStdout <$> qList [1..3] -- 1 -- 2 -- 3 --close :: Codensity m (m r) -> m r -- | fmap then close over a Codensity -- --
-- >>> process (glue showStdout) (qList [1..3]) -- 1 -- 2 -- 3 --process :: (a -> m r) -> Codensity m a -> m r -- | fmap then close over a Codensity -- --
-- >>> glue showStdout <$|> qList [1..3] -- 1 -- 2 -- 3 --(<$|>) :: (a -> m r) -> Codensity m a -> m r infixr 3 <$|> -- | apply to a continuation and close. -- --
-- >>> glue <$> (pure showStdout) <*|> qList [1..3] -- 1 -- 2 -- 3 --(<*|>) :: Codensity m (a -> m r) -> Codensity m a -> m r infixr 3 <*|> instance GHC.Base.Semigroup a => GHC.Base.Semigroup (Control.Monad.Codensity.Codensity m a) instance (GHC.Base.Functor m, GHC.Base.Semigroup a, GHC.Base.Monoid a) => GHC.Base.Monoid (Control.Monad.Codensity.Codensity m a) module Box.Functor -- | An endofunctor in the category of endofunctors. -- -- Like MFunctor but without a Monad constraint. class FFunctor (h :: (Type -> Type) -> Type -> Type) foist :: FFunctor h => (forall x. f x -> g x) -> h f a -> h g a -- | Monadically Foldable class FoldableM (t :: (Type -> Type) -> Type -> Type) foldrM :: (FoldableM t, Monad m) => (a -> m b -> m b) -> m b -> t m a -> m b -- | emit module Box.Emitter -- | an Emitter emits values of type Maybe a. Source & -- Producer are also appropriate metaphors. -- -- An Emitter reaches into itself for the value to emit, where itself is -- an opaque thing from the pov of usage. -- --
-- >>> e = Emitter (pure (Just "I'm emitted")) -- -- >>> emit e -- Just "I'm emitted" ---- --
-- >>> emit mempty -- Nothing --newtype Emitter m a Emitter :: m (Maybe a) -> Emitter m a [emit] :: Emitter m a -> m (Maybe a) -- | An Emitter continuation. type CoEmitter m a = Codensity m (Emitter m a) -- | Collect emits into a list, and close on the first Nothing. -- --
-- >>> toListM <$|> qList [1..3] -- [1,2,3] --toListM :: Monad m => Emitter m a -> m [a] -- | A monadic Witherable -- --
-- >>> close $ toListM <$> witherE (\x -> bool (print x >> pure Nothing) (pure (Just x)) (even x)) <$> (qList [1..3]) -- 1 -- 3 -- [2] --witherE :: Monad m => (a -> m (Maybe b)) -> Emitter m a -> Emitter m b -- | Read parse Emitter, returning the original text on error -- --
-- >>> process (toListM . readE) (qList ["1","2","3","four"]) :: IO [Either Text Int] -- [Right 1,Right 2,Right 3,Left "four"] --readE :: (Functor m, Read a) => Emitter m Text -> Emitter m (Either Text a) -- | Convert a list emitter to a (Stateful) element emitter. -- --
-- >>> import Control.Monad.State.Lazy -- -- >>> close $ flip runStateT [] . toListM . unlistE <$> (qList [[0..3],[5..7]]) -- ([0,1,2,3,5,6,7],[]) --unlistE :: Monad m => Emitter m [a] -> Emitter (StateT [a] m) a -- | Take n emits. -- --
-- >>> import Control.Monad.State.Lazy -- -- >>> close $ flip evalStateT 0 <$> toListM . takeE 4 <$> qList [0..] -- [0,1,2,3] --takeE :: Monad m => Int -> Emitter m a -> Emitter (StateT Int m) a -- | Take from an emitter until a predicate. -- --
-- >>> process (toListM . takeUntilE (==3)) (qList [0..]) -- [0,1,2] --takeUntilE :: Monad m => (a -> Bool) -> Emitter m a -> Emitter m a -- | Pop from a State sequence. -- --
-- >>> import qualified Data.Sequence as Seq -- -- >>> import Control.Monad.State.Lazy (evalStateT) -- -- >>> flip evalStateT (Seq.fromList [1..3]) $ toListM pop -- [1,2,3] --pop :: Monad m => Emitter (StateT (Seq a) m) a instance Box.Functor.FFunctor 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) instance Box.Functor.FoldableM Box.Emitter.Emitter -- | commit module Box.Committer -- | A Committer commits values of type a and signals success or -- otherwise. 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. -- --
-- >>> commit toStdout "I'm committed!" -- I'm committed! -- True --newtype Committer m a Committer :: (a -> m Bool) -> Committer m a [commit] :: Committer m a -> a -> m Bool -- | Committer continuation. type CoCommitter m a = Codensity m (Committer m a) -- | A monadic Witherable -- --
-- >>> glue (witherC (\x -> pure $ bool Nothing (Just x) (even x)) showStdout) <$|> qList [0..5] -- 0 -- 2 -- 4 --witherC :: Monad m => (b -> m (Maybe a)) -> Committer m a -> Committer m b -- | Convert a committer to be a list committer. Think mconcat. -- --
-- >>> glue showStdout <$|> qList [[1..3]] -- [1,2,3] ---- --
-- >>> glue (listC showStdout) <$|> qList [[1..3]] -- 1 -- 2 -- 3 --listC :: Monad m => Committer m a -> Committer m [a] -- | Push to a state sequence. -- --
-- >>> import Control.Monad.State.Lazy -- -- >>> import qualified Data.Sequence as Seq -- -- >>> flip execStateT Seq.empty . glue push . foist lift <$|> qList [1..3] -- fromList [1,2,3] --push :: Monad m => Committer (StateT (Seq a) m) a instance Box.Functor.FFunctor 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 box is something that commits and emits module Box.Box -- | A Box is a product of a Committer and an Emitter. -- -- Think of a box with an incoming arrow an outgoing arrow. And then make -- your pov ambiguous: are you looking at two wires from "inside a box"; -- or are you looking from "outside the box"; interacting with a black -- box object. Either way, it looks the same: it's a box. -- -- And either way, one of the arrows, the Committer, is -- contravariant and the other, the Emitter is covariant. The -- combination is a profunctor. 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 box continuation type CoBox m a b = Codensity m (Box m a b) -- | Wrapper for the semigroupoid instance of a box continuation. newtype CoBoxM m a b CoBoxM :: Codensity m (Box m a b) -> CoBoxM m a b [uncobox] :: CoBoxM m a b -> Codensity m (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' -- | Wrong kind signature for the FFunctor class foistb :: (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. -- --
-- >>> glue showStdout <$|> qList [1..3] -- 1 -- 2 -- 3 --glue :: Monad m => Committer m a -> Emitter m a -> m () -- | Glues a committer and emitter, and takes n emits -- --
-- >>> glueN 3 <$> pure showStdout <*|> qList [1..] -- 1 -- 2 -- 3 ---- -- Note that glueN counts the number of events passing across the -- connection and doesn't take into account post-transmission activity in -- the Committer, eg -- --
-- >>> glueN 4 (witherC (\x -> bool (pure Nothing) (pure (Just x)) (even x)) showStdout) <$|> qList [0..9] -- 0 -- 2 --glueN :: Monad m => Int -> Committer m a -> Emitter m a -> m () -- | Glue a Committer to an Emitter within a box. -- --
-- fuse (pure . pure) == \(Box c e) -> glue c e ---- -- A command-line echoer -- --
-- fuse (pure . Just . ("echo " <>)) (Box toStdout fromStdin)
--
fuse :: Monad m => (a -> m (Maybe b)) -> Box m b a -> m ()
-- | combines divide conquer and liftA2 pure
class Divap p
divap :: Divap p => (a -> (b, c)) -> ((d, e) -> f) -> p b d -> p c e -> p a f
conpur :: Divap p => a -> p b a
-- | combines Decidable and Alternative
class Profunctor p => DecAlt p
choice :: DecAlt p => (a -> Either b c) -> (Either d e -> f) -> p b d -> p c e -> p a f
loss :: DecAlt p => p Void b
-- | Construct a CoBox
--
-- -- cobox = Box <$> c <*> e ---- --
-- >>> fuse (pure . Just . ("show: " <>) . pack . show) <$|> (cobox (pure toStdout) (qList [1..3]))
-- show: 1
-- show: 2
-- show: 3
--
cobox :: CoCommitter m a -> CoEmitter m b -> CoBox m a b
-- | State monad queue.
seqBox :: Monad m => Box (StateT (Seq a) m) a a
instance GHC.Base.Monad m => Data.Semigroupoid.Semigroupoid (Box.Box.CoBoxM m)
instance (GHC.Base.Monad m, GHC.Base.Alternative m) => Box.Box.DecAlt (Box.Box.Box m)
instance GHC.Base.Applicative m => Box.Box.Divap (Box.Box.Box m)
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)
-- | STM Queues, based originally on 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 result from the Committer
-- action.
--
-- -- >>> queueL New (\c -> glue c <$|> qList [1..3]) toListM --queueL :: MonadConc m => Queue a -> (Committer m a -> m l) -> (Emitter m a -> m r) -> m l -- | Create an unbounded queue, returning the result from the Emitter -- action. -- --
-- >>> queueR New (\c -> glue c <$|> qList [1..3]) toListM -- [3] --queueR :: MonadConc m => Queue a -> (Committer m a -> m l) -> (Emitter m a -> m r) -> m r -- | Create an unbounded queue, returning both results. -- --
-- >>> queue Unbounded (\c -> glue c <$|> qList [1..3]) toListM -- ((),[1,2,3]) --queue :: MonadConc m => Queue a -> (Committer m a -> m l) -> (Emitter m a -> m r) -> m (l, r) -- | Turn a box action into a box continuation fromAction :: MonadConc m => (Box m a b -> m r) -> CoBox m b a -- | Hook a committer action to a queue, creating an emitter continuation. emitQ :: MonadConc m => Queue a -> (Committer m a -> m r) -> CoEmitter m a -- | Hook a committer action to a queue, creating an emitter continuation. commitQ :: MonadConc m => Queue a -> (Emitter m a -> m r) -> CoCommitter m a -- | Various ways to connect things up. module Box.Connectors -- | Queue a list. -- --
-- >>> pushList <$|> qList [1,2,3] -- [1,2,3] --qList :: MonadConc m => [a] -> CoEmitter m a -- | Directly supply a list to a committer action, via pop. -- --
-- >>> popList [1..3] showStdout -- 1 -- 2 -- 3 --popList :: Monad m => [a] -> Committer m a -> m () -- | Push an Emitter into a list, via push. -- --
-- >>> pushList <$|> qList [1..3] -- [1,2,3] --pushList :: Monad m => Emitter m a -> m [a] -- | Push an Emitter into a list, finitely. -- --
-- >>> pushListN 2 <$|> qList [1..3] -- [1,2] --pushListN :: Monad m => Int -> Emitter m a -> m [a] -- | Create a finite Committer. -- --
-- >>> glue <$> sink 2 print <*|> qList [1..3] -- 1 -- 2 --sink :: MonadConc m => Int -> (a -> m ()) -> CoCommitter m a -- | Create a finite Emitter. -- --
-- >>> glue toStdout <$|> source 2 (pure "hi") -- hi -- hi --source :: MonadConc m => Int -> m a -> CoEmitter m a -- | Glues an emitter to a committer, then resupplies the emitter. -- --
-- >>> (c1,l1) <- refCommitter :: IO (Committer IO Int, IO [Int]) -- -- >>> close $ toListM <$> (forkEmit <$> (qList [1..3]) <*> pure c1) -- [1,2,3] ---- --
-- >>> l1 -- [1,2,3] --forkEmit :: Monad m => Emitter m a -> Committer m a -> Emitter m a -- | Buffer a committer. bufferCommitter :: MonadConc m => Committer m a -> CoCommitter m a -- | Buffer an emitter. bufferEmitter :: MonadConc m => Emitter m a -> CoEmitter m a -- | Concurrently run two emitters. -- -- This differs to (<>), which is left-biased. -- -- Note that functions such as toListM, which complete on the first -- Nothing emitted, will not work as expected. -- --
-- >>> close $ (fmap toListM) (join $ concurrentE Single <$> qList [1..3] <*> qList [5..9]) -- [1,2,3] ---- -- In the code below, the ordering is non-deterministic. -- --
-- (c,l) <- refCommitter :: IO (Committer IO Int, IO [Int]) -- close $ glue c <$> (join $ concurrentE Single <$> qList [1..30] <*> qList [40..60]) --concurrentE :: MonadConc f => Queue a -> Emitter f a -> Emitter f a -> CoEmitter f a -- | Concurrently run two committers. -- --
-- >>> import Data.Functor.Contravariant
--
-- >>> import Data.Text (pack)
--
-- >>> cFast = witherC (\b -> pure (Just b)) . contramap ("fast: " <>) $ toStdout
--
-- >>> cSlow = witherC (\b -> sleep 0.1 >> pure (Just b)) . contramap ("slow: " <>) $ toStdout
--
-- >>> close $ (popList ((pack . show) <$> [1..3]) <$> (concurrentC Unbounded cFast cSlow)) <> pure (sleep 1)
-- fast: 1
-- fast: 2
-- fast: 3
-- slow: 1
-- slow: 2
-- slow: 3
--
concurrentC :: MonadConc m => Queue a -> Committer m a -> Committer m a -> CoCommitter m a
-- | IO effects
module Box.IO
-- | Emit text from stdin
--
-- -- λ> emit fromStdin -- hello -- Just "hello" --fromStdin :: Emitter IO Text -- | Commit to stdout -- --
-- >>> commit toStdout ("I'm committed!" :: Text)
-- I'm committed!
-- True
--
toStdout :: Committer IO Text
-- | Finite console emitter
--
-- -- λ> toListM <$|> fromStdinN 2 -- hello -- hello again -- ["hello","hello again"] --fromStdinN :: Int -> CoEmitter IO Text -- | Finite console committer -- --
-- >>> glue <$> contramap (pack . show) <$> (toStdoutN 2) <*|> qList [1..3] -- 1 -- 2 --toStdoutN :: Int -> CoCommitter IO Text -- | Read from console, throwing away read errors -- -- λ> glueN 2 showStdout (readStdin :: Emitter IO Int) 1 1 hippo 2 readStdin :: Read a => Emitter IO a -- | Show to stdout -- --
-- >>> glue showStdout <$|> qList [1..3] -- 1 -- 2 -- 3 --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 an IORef -- --
-- >>> (c1,l1) <- refCommitter :: IO (Committer IO Int, IO [Int]) -- -- >>> glue c1 <$|> qList [1..3] -- -- >>> l1 -- [1,2,3] --refCommitter :: MonadConc m => m (Committer m a, m [a]) -- | Emit from a list IORef -- --
-- >>> e <- refEmitter [1..3] -- -- >>> toListM e -- [1,2,3] --refEmitter :: MonadConc m => [a] -> m (Emitter m a) -- | Emit lines of Text from a file. fileE :: FilePath -> CoEmitter IO Text -- | Commit lines of Text to a file. fileWriteC :: FilePath -> CoCommitter IO Text -- | Commit lines of Text, appending to a file. fileAppendC :: FilePath -> CoCommitter IO Text -- | Timing effects. module Box.Time -- | Sleep for x seconds. sleep :: MonadConc m => Double -> m () -- | 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 (LocalTime, a) -- | Add the current time stamp. -- --
-- > process (toListM . stampE) (qList [1..3]) -- [(2022-02-09 01:18:00.293883,1),(2022-02-09 01:18:00.293899,2),(2022-02-09 01:18:00.293903,3)] --stampE :: (MonadConc m, MonadIO m) => Emitter m a -> Emitter m (LocalTime, a) -- | Wait s seconds before emitting emitIn :: Emitter IO (Double, a) -> Emitter IO a -- | Replay a stamped emitter, adjusting the speed of the replay. -- --
-- > glueN 4 showStdout $| replay 1 (Emitter $ sleep 0.1 >> Just $ stampNow ()) --replay :: Double -> Emitter IO (LocalTime, a) -> CoEmitter 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) -- | A profunctor effect -- -- “Boxes are surprisingly bulky. Discard or recycle the box your cell -- phone comes in as soon as you unpack it. You don’t need the manual or -- the CD that comes with it either. You’ll figure out the applications -- you need through using it.” — Marie Kondo module Box