box-0.7.0: src/Box/Emitter.hs
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -Wall #-}
{-# OPTIONS_GHC -fno-warn-type-defaults #-}
-- | `emit`
module Box.Emitter
( Emitter (..),
mapE,
readE,
readE_,
parseE,
parseE_,
premapE,
postmapE,
postmapM,
toListE,
unlistE,
stateE,
takeE,
takeUntilE,
filterE,
)
where
import Control.Applicative
import Control.Monad.Morph
import Control.Monad.State.Lazy
import qualified Data.Attoparsec.Text as A
import Data.Bool
import Data.Foldable
import qualified Data.Sequence as Seq
import Data.Text (Text, pack, unpack)
import Prelude
-- | 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
{ emit :: m (Maybe a)
}
instance MFunctor Emitter where
hoist nat (Emitter e) = Emitter (nat e)
instance (Functor m) => Functor (Emitter m) where
fmap f m = Emitter (fmap (fmap f) (emit m))
instance (Applicative m) => Applicative (Emitter m) where
pure r = Emitter (pure (pure r))
mf <*> mx = Emitter ((<*>) <$> emit mf <*> emit mx)
instance (Monad m) => Monad (Emitter m) where
return r = Emitter (return (return r))
m >>= f =
Emitter $ do
ma <- emit m
case ma of
Nothing -> return Nothing
Just a -> emit (f a)
instance (Monad m, Alternative m) => Alternative (Emitter m) where
empty = Emitter (pure Nothing)
x <|> y =
Emitter $ do
(i, ma) <- fmap ((,) y) (emit x) <|> fmap ((,) x) (emit y)
case ma of
Nothing -> emit i
Just a -> pure (Just a)
instance (Alternative m, Monad m) => MonadPlus (Emitter m) where
mzero = empty
mplus = (<|>)
instance (Alternative m, Monad m) => Semigroup (Emitter m a) where
(<>) = (<|>)
instance (Alternative m, Monad m) => Monoid (Emitter m a) where
mempty = empty
mappend = (<>)
-- | like a monadic mapMaybe. (See [witherable](https://hackage.haskell.org/package/witherable))
mapE :: (Monad m) => (a -> m (Maybe b)) -> Emitter m a -> Emitter m b
mapE f e = Emitter go
where
go = do
a <- emit e
case a of
Nothing -> pure Nothing
Just a' -> do
fa <- f a'
case fa of
Nothing -> go
Just fa' -> pure (Just fa')
-- | parse emitter which returns the original text on failure
parseE :: (Functor m) => A.Parser a -> Emitter m Text -> Emitter m (Either Text a)
parseE parser e = (\t -> either (const $ Left t) Right (A.parseOnly parser t)) <$> e
-- | no error-reporting parsing
parseE_ :: (Monad m) => A.Parser a -> Emitter m Text -> Emitter m a
parseE_ parser = mapE (pure . either (const Nothing) Just) . parseE parser
-- | read parse emitter, returning the original string on error
readE ::
(Functor m, Read a) =>
Emitter m Text ->
Emitter m (Either Text a)
readE = fmap $ parsed . unpack
where
parsed str =
case reads str of
[(a, "")] -> Right a
_err -> Left (pack str)
-- | no error-reporting reading
readE_ ::
(Monad m, Read a) =>
Emitter m Text ->
Emitter m a
readE_ = mapE (pure . either (const Nothing) Just) . readE
-- | adds a pre-emit monadic action to the emitter
premapE ::
(Applicative m) =>
(Emitter m a -> m ()) ->
Emitter m a ->
Emitter m a
premapE f e = Emitter $ f e *> emit e
-- | adds a post-emit monadic action to the emitter
postmapE ::
(Monad m) =>
(Emitter m a -> m ()) ->
Emitter m a ->
Emitter m a
postmapE f e = Emitter $ do
r <- emit e
f e
pure r
-- | 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
postmapM f e = Emitter $ do
r <- emit e
case r of
Nothing -> pure Nothing
Just r' -> do
f r'
pure (Just r')
-- | turn an emitter into a list
toListE :: (Monad m) => Emitter m a -> m [a]
toListE e = go Seq.empty e
where
go xs e' = do
x <- emit e'
case x of
Nothing -> pure (toList xs)
Just x' -> go (xs Seq.:|> x') e'
-- | emit from a StateT Seq
--
-- FIXME: This compiles but is an infinite "a" emitter:
--
-- let e1 = hoist (flip evalStateT (Seq.fromList ["a", "b"::Text])) stateE :: Emitter IO Text
stateE :: (Monad m) => Emitter (StateT (Seq.Seq a) m) a
stateE = Emitter $ do
xs' <- get
case xs' of
Seq.Empty -> pure Nothing
(x Seq.:<| xs'') -> do
put xs''
pure $ Just x
-- | convert a list emitter to a Stateful element emitter
unlistE :: (Monad m) => Emitter m [a] -> Emitter (StateT [a] m) a
unlistE es = mapE unlistS (hoist lift es)
where
unlistS xs = do
rs <- get
case rs <> xs of
[] -> pure Nothing
(x : xs') -> do
put xs'
pure (Just x)
-- | Stop an 'Emitter' after n 'emit's
takeE :: (Monad m) => Int -> Emitter m a -> Emitter (StateT Int m) a
takeE n e = Emitter $ do
x <- emit (hoist lift e)
case x of
Nothing -> pure Nothing
Just x' -> do
n' <- get
bool (pure Nothing) (emit' n') (n' < n)
where
emit' n' = do
put (n' + 1)
pure $ Just x'
-- | Take from an emitter until predicate
takeUntilE :: (Monad m) => (a -> Bool) -> Emitter m a -> Emitter m a
takeUntilE p e = Emitter $ do
x <- emit e
case x of
Nothing -> pure Nothing
Just x' ->
bool (pure (Just x')) (pure Nothing) (p x')
-- | Filter emissions according to a predicate.
filterE :: (Monad m) => (a -> Bool) -> Emitter m a -> Emitter m a
filterE p e = Emitter go
where
go = do
x <- emit e
case x of
Nothing -> pure Nothing
Just x' ->
bool go (pure (Just x')) (p x')