-- 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]))))
--   
-- -- gaps :: Emitter IO (LocalTime, a) -> CoEmitter IO (Gap, a) -- | Convert gaps in seconds to stamps starting from an initial supplied -- LocalTime fromGaps :: LocalTime -> Emitter IO (Gap, a) -> CoEmitter IO (LocalTime, a) -- | Convert gaps in seconds to stamps starting with current time -- --
--   toListM <$|> (fromGapsNow =<< (qList (zip (0:repeat 1) [1..4])))
--   
-- -- fromGapsNow :: Emitter IO (Gap, a) -> CoEmitter IO (LocalTime, a) -- | Convert a (Gap,a) emitter to an a emitter, with delays between emits -- of the gap. gapEffect :: Emitter IO (Gap, a) -> Emitter IO a skip :: Int -> Emitter IO (Gap, a) -> CoEmitter IO (Gap, a) -- | Replay a stamped emitter, adjusting the speed of the replay. -- --
--   toListM . stampE <$|> (replay 0.1 1 =<< (fromGapsNow =<< (qList (zip (0:repeat 1) [1..4]))))
--   
-- -- replay :: Double -> Int -> Emitter IO (LocalTime, a) -> CoEmitter IO a -- | Only add a Gap effect if greater than the Int emitter -- -- effect is similar to a fast-forward of the first n emits gapSkipEffect :: Emitter IO Int -> Emitter IO Gap -> CoEmitter IO Gap speedEffect :: Emitter IO Gap -> Emitter IO (Gap, a) -> Emitter IO a -- | Only add a Gap if greater than the Int emitter -- -- effect is similar to a fast-forward of the first n emits speedSkipEffect :: Emitter IO (Int, Gap) -> Emitter IO (Gap, a) -> CoEmitter IO 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