-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | boxes -- -- A profunctor effect @package box @version 0.9.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 :: forall a m r. (a -> m r) -> Codensity m a -> m r -- | fmap then close over a Codensity -- --
-- >>> glue showStdout <$|> qList [1..3] -- 1 -- 2 -- 3 --(<$|>) :: forall a m r. (a -> m r) -> Codensity m a -> m r infixr 0 <$|> -- | 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 -- | Drop n emits. -- --
-- >>> import Control.Monad.State.Lazy -- -- >>> toListM <$|> (dropE 2 =<< qList [0..3]) -- [2,3] --dropE :: Monad m => Int -> Emitter m a -> CoEmitter 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 () -- | Connect a Stateful emitter to a (non-stateful) committer of the same -- type, supplying initial state. -- --
-- >>> glueES 0 (showStdout) <$|> (takeE 2 <$> qList [1..3]) -- 1 -- 2 --glueES :: Monad m => s -> Committer m a -> Emitter (StateT s m) a -> m () -- | Connect a Stateful emitter to a (similarly-stateful) committer of the -- same type, supplying initial state. -- --
-- >>> glueS 0 (foist lift showStdout) <$|> (takeE 2 <$> qList [1..3]) -- 1 -- 2 --glueS :: Monad m => s -> Committer (StateT s m) a -> Emitter (StateT s 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 :: Queue a -> (Committer IO a -> IO l) -> (Emitter IO a -> IO r) -> IO l -- | Create an unbounded queue, returning the result from the Emitter -- action. -- --
-- >>> queueR New (\c -> glue c <$|> qList [1..3]) toListM -- [3] --queueR :: Queue a -> (Committer IO a -> IO l) -> (Emitter IO a -> IO r) -> IO r -- | Create an unbounded queue, returning both results. -- --
-- >>> queue Unbounded (\c -> glue c <$|> qList [1..3]) toListM -- ((),[1,2,3]) --queue :: Queue a -> (Committer IO a -> IO l) -> (Emitter IO a -> IO r) -> IO (l, r) -- | Turn a box action into a box continuation fromAction :: (Box IO a b -> IO r) -> CoBox IO b a -- | Hook a committer action to a queue, creating an emitter continuation. emitQ :: Queue a -> (Committer IO a -> IO r) -> CoEmitter IO a -- | Hook a committer action to a queue, creating an emitter continuation. commitQ :: Queue a -> (Emitter IO a -> IO r) -> CoCommitter IO a -- | Turn a box action into a box continuation fromActionWith :: Queue a -> Queue b -> (Box IO a b -> IO r) -> CoBox IO b a -- | turn a queue into a box (and a seal), and lift from stm to the -- underlying monad. toBoxM :: Queue a -> IO (Box IO a a, IO ()) -- | turn a queue into a box (and a seal) toBoxSTM :: Queue a -> STM (Box STM a a, STM ()) -- | Various ways to connect things up. module Box.Connectors -- | Queue a list Unbounded. -- --
-- >>> pushList <$|> qList [1,2,3] -- [1,2,3] --qList :: [a] -> CoEmitter IO a -- | Queue a list with an explicit Queue. -- --
-- >>> pushList <$|> qListWith Single [1,2,3] -- [1,2,3] --qListWith :: Queue a -> [a] -> CoEmitter IO 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 Unbounded Queue. -- --
-- glue <$> sink 2 print <*|> qList [1..3] ---- -- 1 2 sink :: Int -> (a -> IO ()) -> CoCommitter IO a -- | Create a finite Committer Queue. sinkWith :: Queue a -> Int -> (a -> IO ()) -> CoCommitter IO a -- | Create a finite (Co)Emitter Unbounded Queue. -- --
-- >>> glue toStdout <$|> source 2 (pure "hi") -- hi -- hi --source :: Int -> IO a -> CoEmitter IO a -- | Create a finite (Co)Emitter Unbounded Queue. -- --
-- >>> glue toStdout <$|> sourceWith Single 2 (pure "hi") -- hi -- hi --sourceWith :: Queue a -> Int -> IO a -> CoEmitter IO 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 :: Committer IO a -> CoCommitter IO a -- | Buffer an emitter. bufferEmitter :: Emitter IO a -> CoEmitter IO 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 :: Queue a -> Emitter IO a -> Emitter IO a -> CoEmitter IO 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 :: Queue a -> Committer IO a -> Committer IO a -> CoCommitter IO a
-- | Take and queue n emits.
--
-- -- >>> import Control.Monad.State.Lazy -- -- >>> toListM <$|> (takeQ Single 4 =<< qList [0..]) -- [0,1,2,3] --takeQ :: Queue a -> Int -> Emitter IO a -> CoEmitter IO a -- | queue a stateful emitter, supplying initial state -- --
-- >>> import Control.Monad.State.Lazy -- -- >>> toListM <$|> (evalEmitter 0 <$> takeE 4 =<< qList [0..]) -- [0,1,2,3] --evalEmitter :: s -> Emitter (StateT s IO) a -> CoEmitter IO a -- | queue a stateful emitter, supplying initial state evalEmitterWith :: Queue a -> s -> Emitter (StateT s IO) a -> CoEmitter IO 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 2 readStdin :: Read a => Emitter IO a -- | Show to stdout -- --
-- >>> glue showStdout <$|> qList [1..3] -- 1 -- 2 -- 3 --showStdout :: Show a => Committer IO a -- | Commit to an IORef -- --
-- >>> (c1,l1) <- refCommitter :: IO (Committer IO Int, IO [Int]) -- -- >>> glue c1 <$|> qList [1..3] -- -- >>> l1 -- [1,2,3] --refCommitter :: IO (Committer IO a, IO [a]) -- | Emit from a list IORef -- --
-- >>> e <- refEmitter [1..3] -- -- >>> toListM e -- [1,2,3] --refEmitter :: [a] -> IO (Emitter IO a) -- | Emits lines of Text from a handle. handleEText = handleE Text.hGetLine -- -- Emits lines of Text from a handle. handleE :: (IsString a, Eq a) => (Handle -> IO a) -> Handle -> Emitter IO a -- | Commit lines of Text to a handle. handleC :: (Handle -> a -> IO ()) -> Handle -> Committer IO a -- | Commit lines of Text to a handle. handleCBS = handleC Char8.hPutStrLn -- -- Emits lines of Text from a handle. handleCText = handleC -- Text.hPutStrLn -- -- Emit lines of Text from a file. fileE :: FilePath -> BufferMode -> IOMode -> (Handle -> Emitter IO a) -> CoEmitter IO a -- | Commit lines of Text to a file. fileC :: FilePath -> IOMode -> BufferMode -> (Handle -> Committer IO a) -> CoCommitter IO a fileEText :: FilePath -> BufferMode -> CoEmitter IO Text fileEBS :: FilePath -> BufferMode -> CoEmitter IO ByteString fileCText :: FilePath -> BufferMode -> IOMode -> CoCommitter IO Text fileCBS :: FilePath -> BufferMode -> IOMode -> CoCommitter IO ByteString -- | simple console logger for rough testing logConsoleC :: Show a => String -> Committer IO a -> Committer IO a -- | simple console logger for rough testing logConsoleE :: Show a => String -> Emitter IO a -> Emitter IO a -- | Pause an emitter based on a Bool emitter pauser :: Emitter IO Bool -> Emitter IO a -> Emitter IO a -- | Create an emitter that indicates when another emitter has changed. changer :: Eq a => a -> Emitter IO a -> CoEmitter IO Bool -- | quit a process based on a Bool emitter -- --
-- quit <$> speedEffect (pure 2) <$> (resetGap 5) <*|> pure io ---- -- 0 1 2 3 4 Left True quit :: Emitter IO Bool -> IO a -> IO (Either Bool a) -- | restart a process if flagged by a Bool emitter restart :: Emitter IO Bool -> IO a -> IO (Either Bool a) -- | Timing effects. module Box.Time -- | Sleep for x seconds. sleep :: Double -> IO () -- | Add the current time stampNow :: a -> IO (LocalTime, a) -- | Add the current time stamp. -- --
-- > toListM . stampE $| (qList [1..3]) -- [(2022-08-30 01:55:16.517127,1),(2022-08-30 01:55:16.517132,2),(2022-08-30 01:55:16.517135,3)] --stampE :: Emitter IO a -> Emitter IO (LocalTime, a) type Gap = Double -- | Convert stamped emitter to gap between emits in seconds -- --
-- toListM <$|> (gaps =<< (fromGapsNow =<< (qList (zip (0:repeat 1) [1..4])))) ---- --
-- toListM <$|> (fromGapsNow =<< (qList (zip (0:repeat 1) [1..4]))) ---- --
-- toListM . stampE <$|> (replay 0.1 1 =<< (fromGapsNow =<< (qList (zip (0:repeat 1) [1..4])))) ---- --