module Control.Concurrent.SCC.Types (
Performer(..),
OpenConsumer, Consumer(..), OpenProducer, Producer(..),
OpenTransducer, Transducer(..), OpenSplitter, Splitter(..),
Boundary(..), Markup(..), Parser,
PipeableComponentPair (compose), Branching (combineBranches),
isolateConsumer, isolateProducer, isolateTransducer, isolateSplitter,
oneToOneTransducer, statelessTransducer, statelessChunkTransducer, statefulTransducer,
statelessSplitter, statefulSplitter,
)
where
import Control.Category (Category(id), (>>>))
import qualified Control.Category as Category
import Control.Monad (liftM)
import Data.Monoid (Monoid(..))
import Control.Monad.Coroutine
import Data.Monoid.Null (MonoidNull)
import Data.Monoid.Factorial (FactorialMonoid)
import Control.Concurrent.SCC.Streams
type OpenConsumer m a d x r = (AncestorFunctor a d, Monoid x) => Source m a x -> Coroutine d m r
type OpenProducer m a d x r = (AncestorFunctor a d, Monoid x) => Sink m a x -> Coroutine d m r
type OpenTransducer m a1 a2 d x y r =
(AncestorFunctor a1 d, AncestorFunctor a2 d, Monoid x, Monoid y) => Source m a1 x -> Sink m a2 y -> Coroutine d m r
type OpenSplitter m a1 a2 a3 d x r =
(AncestorFunctor a1 d, AncestorFunctor a2 d, AncestorFunctor a3 d, Monoid x) =>
Source m a1 x -> Sink m a2 x -> Sink m a3 x -> Coroutine d m r
newtype Performer m r = Performer {perform :: m r}
newtype Consumer m x r = Consumer {consume :: forall a d. OpenConsumer m a d x r}
newtype Producer m x r = Producer {produce :: forall a d. OpenProducer m a d x r}
newtype Transducer m x y = Transducer {transduce :: forall a1 a2 d. OpenTransducer m a1 a2 d x y ()}
newtype Splitter m x = Splitter {split :: forall a1 a2 a3 d. OpenSplitter m a1 a2 a3 d x ()}
data Boundary y = Start y | End y | Point y deriving (Eq, Show)
data Markup y x = Content x | Markup (Boundary y) deriving (Eq)
type Parser m x b = Transducer m x [Markup b x]
instance Functor Boundary where
fmap f (Start b) = Start (f b)
fmap f (End b) = End (f b)
fmap f (Point b) = Point (f b)
instance Functor (Markup y) where
fmap f (Content x) = Content (f x)
fmap _ (Markup b) = Markup b
instance (Show x , Show y) => Show (Markup y x) where
showsPrec _ (Content x) s = shows x s
showsPrec _ (Markup b) s = '[' : shows b (']' : s)
isolateConsumer :: forall m x r. (Monad m, Monoid x) =>
(forall d. Functor d => Source m d x -> Coroutine d m r) -> Consumer m x r
isolateConsumer c = Consumer consume'
where consume' :: forall a d. OpenConsumer m a d x r
consume' source = let source' :: Source m d x
source' = liftSource source
in c source'
isolateProducer :: forall m x r. (Monad m, Monoid x) =>
(forall d. Functor d => Sink m d x -> Coroutine d m r) -> Producer m x r
isolateProducer p = Producer produce'
where produce' :: forall a d. OpenProducer m a d x r
produce' sink = let sink' :: Sink m d x
sink' = liftSink sink
in p sink'
isolateTransducer :: forall m x y. (Monad m, Monoid x) =>
(forall d. Functor d => Source m d x -> Sink m d y -> Coroutine d m ()) -> Transducer m x y
isolateTransducer t = Transducer transduce'
where transduce' :: forall a1 a2 d. OpenTransducer m a1 a2 d x y ()
transduce' source sink = let source' :: Source m d x
source' = liftSource source
sink' :: Sink m d y
sink' = liftSink sink
in t source' sink'
isolateSplitter :: forall m x b. (Monad m, Monoid x) =>
(forall d. Functor d => Source m d x -> Sink m d x -> Sink m d x -> Coroutine d m ())
-> Splitter m x
isolateSplitter s = Splitter split'
where split' :: forall a1 a2 a3 d. OpenSplitter m a1 a2 a3 d x ()
split' source true false = let source' :: Source m d x
source' = liftSource source
true' :: Sink m d x
true' = liftSink true
false' :: Sink m d x
false' = liftSink false
in s source' true' false'
class PipeableComponentPair (m :: * -> *) w c1 c2 c3 | c1 c2 -> c3, c1 c3 -> c2, c2 c3 -> c2,
c1 -> m w, c2 -> m w, c3 -> m
where compose :: PairBinder m -> c1 -> c2 -> c3
instance forall m x. (Monad m, Monoid x) =>
PipeableComponentPair m x (Producer m x ()) (Consumer m x ()) (Performer m ())
where compose binder p c = let performPipe :: Coroutine Naught m ((), ())
performPipe = pipeG binder (produce p) (consume c)
in Performer (runCoroutine performPipe >> return ())
instance forall m x r. (Monad m, Monoid x) =>
PipeableComponentPair m x (Producer m x ()) (Consumer m x r) (Performer m r)
where compose binder p c = let performPipe :: Coroutine Naught m ((), r)
performPipe = pipeG binder (produce p) (consume c)
in Performer (liftM snd $ runCoroutine performPipe)
instance forall m x r. (Monad m, Monoid x) =>
PipeableComponentPair m x (Producer m x r) (Consumer m x ()) (Performer m r)
where compose binder p c = let performPipe :: Coroutine Naught m (r, ())
performPipe = pipeG binder (produce p) (consume c)
in Performer (liftM fst $ runCoroutine performPipe)
instance (Monad m, Monoid x, Monoid y) =>
PipeableComponentPair m y (Transducer m x y) (Consumer m y r) (Consumer m x r)
where compose binder t c = isolateConsumer $ \source->
liftM snd $
pipeG binder
(transduce t source)
(consume c)
instance (Monad m, Monoid x, Monoid y) =>
PipeableComponentPair m x (Producer m x r) (Transducer m x y) (Producer m y r)
where compose binder p t = isolateProducer $ \sink->
liftM fst $
pipeG binder
(produce p)
(\source-> transduce t source sink)
instance (Monad m, Monoid x, Monoid y, Monoid z) =>
PipeableComponentPair m y (Transducer m x y) (Transducer m y z) (Transducer m x z)
where compose binder t1 t2 =
isolateTransducer $ \source sink->
pipeG binder (transduce t1 source) (\source'-> transduce t2 source' sink)
>> return ()
class Branching c (m :: * -> *) x r | c -> m x where
combineBranches :: (forall d. (PairBinder m ->
(forall a d'. AncestorFunctor d d' => OpenConsumer m a d' x r) ->
(forall a d'. AncestorFunctor d d' => OpenConsumer m a d' x r) ->
(forall a. OpenConsumer m a d x r))) ->
PairBinder m -> c -> c -> c
instance forall m x r. Monad m => Branching (Consumer m x r) m x r where
combineBranches combinator binder c1 c2 = Consumer $ combinator binder (consume c1) (consume c2)
instance forall m x y. Monad m => Branching (Transducer m x y) m x () where
combineBranches combinator binder t1 t2
= let transduce' :: forall a1 a2 d. OpenTransducer m a1 a2 d x y ()
transduce' source sink = combinator binder
(\source'-> transduce t1 source' sink')
(\source'-> transduce t2 source' sink')
source
where sink' :: Sink m d y
sink' = liftSink sink
in Transducer transduce'
instance forall m x b. Monad m => Branching (Splitter m x) m x () where
combineBranches combinator binder s1 s2
= let split' :: forall a1 a2 a3 d. OpenSplitter m a1 a2 a3 d x ()
split' source true false = combinator binder
(\source'-> split s1 source' true' false')
(\source'-> split s2 source' true' false')
source
where true' :: Sink m d x
true' = liftSink true
false' :: Sink m d x
false' = liftSink false
in Splitter split'
oneToOneTransducer :: (Monad m, FactorialMonoid x, Monoid y) => (x -> y) -> Transducer m x y
oneToOneTransducer f = Transducer (mapStream f)
statelessTransducer :: Monad m => (x -> y) -> Transducer m [x] y
statelessTransducer f = Transducer (mapStream (mconcat . map f))
statelessChunkTransducer :: Monad m => (x -> y) -> Transducer m x y
statelessChunkTransducer f = Transducer (mapStreamChunks f)
statefulTransducer :: (Monad m, MonoidNull y) => (state -> x -> (state, y)) -> state -> Transducer m [x] y
statefulTransducer f s0 =
Transducer (\source sink-> foldMStream_ (\ s x -> let (s', ys) = f s x in putAll ys sink >> return s') s0 source)
statelessSplitter :: Monad m => (x -> Bool) -> Splitter m [x]
statelessSplitter f = Splitter (\source true false-> partitionStream f source true false)
statefulSplitter :: Monad m => (state -> x -> (state, Bool)) -> state -> Splitter m [x]
statefulSplitter f s0 =
Splitter (\source true false->
foldMStream_
(\ s x -> let (s', truth) = f s x in (if truth then put true x else put false x) >> return s')
s0 source)