module Control.Concurrent.SCC.Combinators (
consumeBy, prepend, append, substitute,
JoinableComponentPair (join, sequence),
sNot,
sAnd, sOr,
pAnd, pOr,
ifs, wherever, unless, select,
while, nestedIn,
foreach, having, havingOnly, followedBy, even,
first, uptoFirst, prefix,
last, lastAndAfter, suffix,
startOf, endOf, between,
splitterToMarker, splittersToPairMarker, parserToSplitter, parseRegions,
groupMarks, findsTrueIn, findsFalseIn, teeConsumers
)
where
import Prelude hiding (drop, even, join, last, length, map, null, sequence)
import Control.Monad (liftM, void, when)
import Control.Monad.Trans.Class (lift)
import Data.Maybe (isJust, mapMaybe)
import Data.Monoid (Monoid, mempty, mconcat)
import qualified Data.Foldable as Foldable
import qualified Data.List as List (map)
import qualified Data.Sequence as Seq
import Data.Sequence (Seq, (<|), (|>), (><), ViewL (EmptyL, (:<)))
import Control.Monad.Coroutine
import Data.Monoid.Null (MonoidNull(null))
import Data.Monoid.Factorial (FactorialMonoid, length, drop)
import Control.Concurrent.SCC.Streams
import Control.Concurrent.SCC.Types
import Control.Concurrent.SCC.Coercions
consumeBy :: forall m x y r. (Monad m) => Consumer m x r -> Transducer m x y
consumeBy c = Transducer $ \ source _sink -> consume c source >> return ()
class CompatibleSignature c cons (m :: * -> *) input output | c -> cons m
instance CompatibleSignature (Performer m r) (PerformerType r) m x y
instance CompatibleSignature (Consumer m x r) (ConsumerType r) m x y
instance CompatibleSignature (Producer m x r) (ProducerType r) m y x
instance CompatibleSignature (Transducer m x y) TransducerType m x y
data PerformerType r
data ConsumerType r
data ProducerType r
data TransducerType
class (Monad m, CompatibleSignature c1 t1 m x y, CompatibleSignature c2 t2 m x y, CompatibleSignature c3 t3 m x y)
=> JoinableComponentPair t1 t2 t3 m x y c1 c2 c3 | c1 c2 -> c3, c1 -> t1 m, c2 -> t2 m, c3 -> t3 m x y,
t1 m x y -> c1, t2 m x y -> c2, t3 m x y -> c3
where
join :: PairBinder m -> c1 -> c2 -> c3
join = const sequence
sequence :: c1 -> c2 -> c3
instance forall m x r1 r2. Monad m =>
JoinableComponentPair (ProducerType r1) (ProducerType r2) (ProducerType r2) m () x
(Producer m x r1) (Producer m x r2) (Producer m x r2)
where sequence p1 p2 = Producer $ \sink-> produce p1 sink >> produce p2 sink
instance forall m x. Monad m =>
JoinableComponentPair (ConsumerType ()) (ConsumerType ()) (ConsumerType ()) m x ()
(Consumer m x ()) (Consumer m x ()) (Consumer m x ())
where join binder c1 c2 = Consumer (liftM (const ()) . teeConsumers binder (consume c1) (consume c2))
sequence c1 c2 = Consumer $ \source->
teeConsumers sequentialBinder (consume c1) getAll source
>>= \((), list)-> pipe (flip putChunk list) (consume c2)
>> return ()
instance forall m x y. (Monad m, Monoid x, Monoid y) =>
JoinableComponentPair TransducerType TransducerType TransducerType m x y
(Transducer m x y) (Transducer m x y) (Transducer m x y)
where join binder t1 t2 = isolateTransducer $ \source sink->
pipe
(\buffer-> teeConsumers binder
(\source'-> transduce t1 source' sink)
(\source'-> transduce t2 source' buffer)
source)
getAll
>>= \(_, list)-> putChunk sink list
>> return ()
sequence t1 t2 = isolateTransducer $ \source sink->
teeConsumers sequentialBinder (flip (transduce t1) sink) getAll source
>>= \(_, list)-> pipe (flip putChunk list) (\source'-> transduce t2 source' sink)
>> return ()
instance forall m r1 r2. Monad m =>
JoinableComponentPair (PerformerType r1) (PerformerType r2) (PerformerType r2) m () ()
(Performer m r1) (Performer m r2) (Performer m r2)
where join binder p1 p2 = Performer $ binder (const return) (perform p1) (perform p2)
sequence p1 p2 = Performer $ perform p1 >> perform p2
instance forall m x r1 r2. Monad m =>
JoinableComponentPair (PerformerType r1) (ProducerType r2) (ProducerType r2) m () x
(Performer m r1) (Producer m x r2) (Producer m x r2)
where join binder pe pr = Producer $ \sink-> liftBinder binder (const return) (lift (perform pe)) (produce pr sink)
sequence pe pr = Producer $ \sink-> lift (perform pe) >> produce pr sink
instance forall m x r1 r2. Monad m =>
JoinableComponentPair (ProducerType r1) (PerformerType r2) (ProducerType r2) m () x
(Producer m x r1) (Performer m r2) (Producer m x r2)
where join binder pr pe = Producer $ \sink-> liftBinder binder (const return) (produce pr sink) (lift (perform pe))
sequence pr pe = Producer $ \sink-> produce pr sink >> lift (perform pe)
instance forall m x r1 r2. Monad m =>
JoinableComponentPair (PerformerType r1) (ConsumerType r2) (ConsumerType r2) m x ()
(Performer m r1) (Consumer m x r2) (Consumer m x r2)
where join binder p c = Consumer $ \source-> liftBinder binder (const return) (lift (perform p)) (consume c source)
sequence p c = Consumer $ \source-> lift (perform p) >> consume c source
instance forall m x r1 r2. Monad m =>
JoinableComponentPair (ConsumerType r1) (PerformerType r2) (ConsumerType r2) m x ()
(Consumer m x r1) (Performer m r2) (Consumer m x r2)
where join binder c p = Consumer $ \source-> liftBinder binder (const return) (consume c source) (lift (perform p))
sequence c p = Consumer $ \source-> consume c source >> lift (perform p)
instance forall m x y r. Monad m =>
JoinableComponentPair (PerformerType r) TransducerType TransducerType m x y
(Performer m r) (Transducer m x y) (Transducer m x y)
where join binder p t =
Transducer $ \ source sink ->
liftBinder binder (const return) (lift (perform p)) (transduce t source sink)
sequence p t = Transducer $ \ source sink -> lift (perform p) >> transduce t source sink
instance forall m x y r. Monad m
=> JoinableComponentPair TransducerType (PerformerType r) TransducerType m x y
(Transducer m x y) (Performer m r) (Transducer m x y)
where join binder t p =
Transducer $ \ source sink ->
liftBinder binder (const . return) (transduce t source sink) (lift (perform p))
sequence t p = Transducer $ \ source sink -> do result <- transduce t source sink
_ <- lift (perform p)
return result
instance forall m x y. (Monad m, Monoid x, Monoid y) =>
JoinableComponentPair (ProducerType ()) TransducerType TransducerType m x y
(Producer m y ()) (Transducer m x y) (Transducer m x y)
where join binder p t =
isolateTransducer $ \source sink->
pipe (\buffer-> liftBinder binder (const return) (produce p sink) (transduce t source buffer)) getAll
>>= \(_, out)-> putChunk sink out >> return ()
sequence p t = Transducer $ \ source sink -> produce p sink >> transduce t source sink
instance forall m x y. (Monad m, Monoid x, Monoid y) =>
JoinableComponentPair TransducerType (ProducerType ()) TransducerType m x y
(Transducer m x y) (Producer m y ()) (Transducer m x y)
where join binder t p =
isolateTransducer $ \source sink->
pipe (\buffer-> liftBinder binder (const . return) (transduce t source sink) (produce p buffer)) getAll
>>= \(_, out)-> putChunk sink out >> return ()
sequence t p = Transducer $ \ source sink -> do result <- transduce t source sink
produce p sink
return result
instance forall m x y. (Monad m, Monoid x, Monoid y) =>
JoinableComponentPair (ConsumerType ()) TransducerType TransducerType m x y
(Consumer m x ()) (Transducer m x y) (Transducer m x y)
where join binder c t =
isolateTransducer $ \source sink->
teeConsumers binder (consume c) (\source'-> transduce t source' sink) source
>> return ()
sequence c t = isolateTransducer $ \source sink->
teeConsumers sequentialBinder (consume c) getAll source
>>= \(_, list)-> pipe (flip putChunk list) (\source'-> transduce t source' sink)
>> return ()
instance forall m x y. (Monad m, Monoid x, Monoid y) =>
JoinableComponentPair TransducerType (ConsumerType ()) TransducerType m x y
(Transducer m x y) (Consumer m x ()) (Transducer m x y)
where join binder t c = join binder c t
sequence t c = isolateTransducer $ \source sink->
teeConsumers sequentialBinder (\source'-> transduce t source' sink) getAll source
>>= \(_, list)-> pipe (flip putChunk list) (consume c)
>> return ()
instance forall m x y. Monad m =>
JoinableComponentPair (ProducerType ()) (ConsumerType ()) TransducerType m x y
(Producer m y ()) (Consumer m x ()) (Transducer m x y)
where join binder p c = Transducer $
\ source sink -> liftBinder binder (\ _ _ -> return ()) (produce p sink) (consume c source)
sequence p c = Transducer $ \ source sink -> produce p sink >> consume c source
instance forall m x y. Monad m =>
JoinableComponentPair (ConsumerType ()) (ProducerType ()) TransducerType m x y
(Consumer m x ()) (Producer m y ()) (Transducer m x y)
where join binder c p = join binder p c
sequence c p = Transducer $ \ source sink -> consume c source >> produce p sink
prepend :: forall m x r. Monad m => Producer m x r -> Transducer m x x
prepend prefixProducer = Transducer $ \ source sink -> produce prefixProducer sink >> pour_ source sink
append :: forall m x r. Monad m => Producer m x r -> Transducer m x x
append suffixProducer = Transducer $ \ source sink -> pour source sink >> produce suffixProducer sink >> return ()
substitute :: forall m x y r. (Monad m, Monoid x) => Producer m y r -> Transducer m x y
substitute feed = Transducer $
\ source sink -> mapMStreamChunks_ (const $ return ()) source >> produce feed sink >> return ()
sNot :: forall m x. (Monad m, Monoid x) => Splitter m x -> Splitter m x
sNot splitter = isolateSplitter s
where s :: forall d. Functor d => Source m d x -> Sink m d x -> Sink m d x -> Coroutine d m ()
s source true false = split splitter source false true
sAnd :: forall m x. (Monad m, Monoid x) => PairBinder m -> Splitter m x -> Splitter m x -> Splitter m x
sAnd binder s1 s2 =
isolateSplitter $ \ source true false ->
liftM fst $
pipeG binder
(\true'-> split s1 source true' false)
(\source'-> split s2 source' true false)
sOr :: forall m x. (Monad m, Monoid x) => PairBinder m -> Splitter m x -> Splitter m x -> Splitter m x
sOr binder s1 s2 =
isolateSplitter $ \ source true false ->
liftM fst $
pipeG binder
(\false'-> split s1 source true false')
(\source'-> split s2 source' true false)
pAnd :: forall m x. (Monad m, FactorialMonoid x) => PairBinder m -> Splitter m x -> Splitter m x -> Splitter m x
pAnd = zipSplittersWith (&&)
pOr :: forall m x. (Monad m, FactorialMonoid x) => PairBinder m -> Splitter m x -> Splitter m x -> Splitter m x
pOr = zipSplittersWith (||)
ifs :: forall c m x. (Monad m, Branching c m x ()) => PairBinder m -> Splitter m x -> c -> c -> c
ifs binder s c1 c2 = combineBranches if' binder c1 c2
where if' :: forall d. PairBinder m -> (forall a d'. AncestorFunctor d d' => OpenConsumer m a d' x ()) ->
(forall a d'. AncestorFunctor d d' => OpenConsumer m a d' x ()) ->
forall a. OpenConsumer m a d x ()
if' binder' c1' c2' source = splitInputToConsumers binder' s source c1' c2'
wherever :: forall m x. (Monad m, Monoid x) => PairBinder m -> Transducer m x x -> Splitter m x -> Transducer m x x
wherever binder t s = isolateTransducer wherever'
where wherever' :: forall d. Functor d => Source m d x -> Sink m d x -> Coroutine d m ()
wherever' source sink = pipeG binder
(\true-> split s source true sink)
(flip (transduce t) sink)
>> return ()
unless :: forall m x. (Monad m, Monoid x) => PairBinder m -> Transducer m x x -> Splitter m x -> Transducer m x x
unless binder t s = wherever binder t (sNot s)
select :: forall m x. (Monad m, Monoid x) => Splitter m x -> Transducer m x x
select s = isolateTransducer t
where t :: forall d. Functor d => Source m d x -> Sink m d x -> Coroutine d m ()
t source sink = split s source sink (nullSink :: Sink m d x)
parseRegions :: forall m x. (Monad m, MonoidNull x) => Splitter m x -> Parser m x ()
parseRegions s = isolateTransducer $ \source sink->
pipe
(transduce (splitterToMarker s) source)
(\source'-> concatMapAccumStream wrap Nothing source' sink
>>= maybe (return ()) (put sink . flush))
>> return ()
where wrap Nothing (x, False) = (Nothing, if null x then [] else [Content x])
wrap Nothing (x, True) | null x = (Just ((), False), [])
| otherwise = (Just ((), True), [Markup (Start ()), Content x])
wrap (Just p) (x, False) = (Nothing, if null x then [flush p] else [flush p, Content x])
wrap (Just (b, t)) (x, True) = (Just (b, True), if t then [Content x] else [Markup (Start b), Content x])
flush (b, t) = Markup $ (if t then End else Point) b
while :: forall m x. (Monad m, MonoidNull x) =>
PairBinder m -> Transducer m x x -> Splitter m x -> Transducer m x x -> Transducer m x x
while binder t s whileRest = isolateTransducer while'
where while' :: forall d. Functor d => Source m d x -> Sink m d x -> Coroutine d m ()
while' source sink =
pipeG binder
(\true'-> split s source true' sink)
(\source'-> getRead readEof source'
>>= flip (when . not) (transduce (compose binder t whileRest) source' sink))
>> return ()
nestedIn :: forall m x. (Monad m, MonoidNull x) =>
PairBinder m -> Splitter m x -> Splitter m x -> Splitter m x -> Splitter m x
nestedIn binder s1 s2 nestedRest =
isolateSplitter $ \ source true false ->
liftM fst $
pipeG binder
(\false'-> split s1 source true false')
(\source'-> pipe
(\true'-> splitInput s2 source' true' false)
(\source''-> getRead readEof source''
>>= flip (when . not) (split nestedRest source'' true false)))
foreach :: forall m x c. (Monad m, MonoidNull x, Branching c m x ()) => PairBinder m -> Splitter m x -> c -> c -> c
foreach binder s c1 c2 = combineBranches foreach' binder c1 c2
where foreach' :: forall d. PairBinder m ->
(forall a d'. AncestorFunctor d d' => OpenConsumer m a d' x ()) ->
(forall a d'. AncestorFunctor d d' => OpenConsumer m a d' x ()) ->
forall a. OpenConsumer m a d x ()
foreach' binder' c1' c2' source =
liftM fst $
pipeG binder'
(transduce (splitterToMarker s) (liftSource source :: Source m d x))
(\source'-> groupMarks source' (\b-> if b then c1' else c2'))
having :: forall m x y. (Monad m, MonoidNull x, MonoidNull y, Coercible x y) =>
PairBinder m -> Splitter m x -> Splitter m y -> Splitter m x
having binder s1 s2 = isolateSplitter s
where s :: forall d. Functor d => Source m d x -> Sink m d x -> Sink m d x -> Coroutine d m ()
s source true false = pipeG binder
(transduce (splitterToMarker s1) source)
(flip groupMarks test)
>> return ()
where test False chunk = pour_ chunk false
test True chunk =
do chunkBuffer <- getAll chunk
(_, found) <- pipe (produce $ adaptProducer $ Producer $ putAll chunkBuffer) (findsTrueIn s2)
if found
then putChunk true chunkBuffer
else putAll chunkBuffer false
return ()
havingOnly :: forall m x y. (Monad m, MonoidNull x, MonoidNull y, Coercible x y) =>
PairBinder m -> Splitter m x -> Splitter m y -> Splitter m x
havingOnly binder s1 s2 = isolateSplitter s
where s :: forall d. Functor d => Source m d x -> Sink m d x -> Sink m d x -> Coroutine d m ()
s source true false = pipeG binder
(transduce (splitterToMarker s1) source)
(flip groupMarks test)
>> return ()
where test False chunk = pour_ chunk false
test True chunk =
do chunkBuffer <- getAll chunk
(_, anyFalse) <-
pipe (produce $ adaptProducer $ Producer $ putAll chunkBuffer) (findsFalseIn s2)
if anyFalse
then putAll chunkBuffer false
else putChunk true chunkBuffer
return ()
first :: forall m x. (Monad m, MonoidNull x) => Splitter m x -> Splitter m x
first splitter = wrapMarkedSplitter splitter $
\source true false->
pourUntil (snd . head) source (markDown false)
>>= Foldable.mapM_
(\_-> pourWhile (snd . head) source (markDown true)
>> concatMapStream fst source false)
uptoFirst :: forall m x. (Monad m, MonoidNull x) => Splitter m x -> Splitter m x
uptoFirst splitter = wrapMarkedSplitter splitter $
\source true false->
do (pfx, mx) <- getUntil (snd . head) source
let prefix' = mconcat $ List.map (\(x, False)-> x) pfx
maybe
(putAll prefix' false >> return ())
(\[x]-> putAll prefix' true
>> pourWhile (snd . head) source (markDown true)
>> concatMapStream fst source false)
mx
last :: forall m x. (Monad m, MonoidNull x) => Splitter m x -> Splitter m x
last splitter =
wrapMarkedSplitter splitter $
\source true false->
let split1 = getUntil (not . snd . head) source >>= split2
split2 (trues, Nothing) = putChunk true (mconcat $ List.map fst trues)
split2 (trues, Just [~(_, False)]) = getUntil (snd . head) source >>= split3 trues
split3 ts (fs, Nothing) = putChunk true (mconcat $ List.map fst ts) >> putAll (mconcat $ List.map fst fs) false
split3 ts (fs, x@Just{}) = putAll (mconcat $ List.map fst ts) false >> putAll (mconcat $ List.map fst fs) false
>> split1
in pourUntil (snd . head) source (markDown false)
>>= Foldable.mapM_ (const split1)
lastAndAfter :: forall m x. (Monad m, MonoidNull x) => Splitter m x -> Splitter m x
lastAndAfter splitter =
wrapMarkedSplitter splitter $
\source true false->
let split1 = getUntil (not . snd . head) source >>= split2
split2 (trues, Nothing) = putChunk true (mconcat $ List.map fst trues)
split2 (trues, Just [~(_, False)]) = getUntil (snd . head) source >>= split3 trues
split3 ts (fs, Nothing) = putChunk true (mconcat $ List.map fst ts) >> putChunk true (mconcat $ List.map fst fs)
split3 ts (fs, x@Just{}) = putAll (mconcat $ List.map fst ts) false >> putAll (mconcat $ List.map fst fs) false
>> split1
in pourUntil (snd . head) source (markDown false)
>>= Foldable.mapM_ (const split1)
prefix :: forall m x. (Monad m, MonoidNull x) => Splitter m x -> Splitter m x
prefix splitter = wrapMarkedSplitter splitter splitMarked
where splitMarked :: forall a1 a2 a3 d. (AncestorFunctor a1 d, AncestorFunctor a2 d, AncestorFunctor a3 d,
AncestorFunctor a1 (SinkFunctor d [(x, Bool)]),
AncestorFunctor a2 (SourceFunctor d [(x, Bool)])) =>
Source m a1 [(x, Bool)] -> Sink m a2 x -> Sink m a3 x -> Coroutine d m ()
splitMarked source true false =
pourUntil (not . null . fst . head) source (nullSink :: Sink m d [(x, Bool)])
>>= maybe
(return ())
(\[x0]-> when (snd x0) (pourWhile (snd . head) source (markDown true))
>> concatMapStream fst source false)
suffix :: forall m x. (Monad m, MonoidNull x) => Splitter m x -> Splitter m x
suffix splitter =
wrapMarkedSplitter splitter $
\source true false->
let split0 = pourUntil (snd . head) source (markDown false)
>>= Foldable.mapM_ (const split1)
split1 = getUntil (not . snd . head) source >>= split2
split2 (trues, Nothing) = putAll (mconcat $ List.map fst trues) true >> return ()
split2 (trues, Just [(x, False)])
| null x = do (_, mr) <- getUntil (not . null . fst . head) source
case mr of Nothing -> putAll (mconcat $ List.map fst trues) true
>> return ()
Just{} -> putAll (mconcat $ List.map fst trues) false
>> split0
| otherwise = putAll (mconcat $ List.map fst trues) false >> split0
in split0
even :: forall m x. (Monad m, MonoidNull x) => Splitter m x -> Splitter m x
even splitter = wrapMarkedSplitter splitter $
\source true false->
let false' = markDown false
split0 = pourUntil (snd . head) source false' >>= split1
split1 Nothing = return ()
split1 (Just [~(_, True)]) = split2
split2 = pourUntil (not . snd . head) source false' >>= split3
split3 Nothing = return ()
split3 (Just [~(_, False)]) = pourUntil (snd . head) source false' >>= split4
split4 Nothing = return ()
split4 (Just [~(_, True)]) = split5
split5 = pourWhile (snd . head) source (markDown true) >> split0
in split0
startOf :: forall m x. (Monad m, MonoidNull x) => Splitter m x -> Splitter m x
startOf splitter = wrapMarkedSplitter splitter $
\source true false->
let false' = markDown false
split0 = pourUntil (snd . head) source false' >>= split1
split1 Nothing = return ()
split1 (Just [~(_, True)]) = putChunk true mempty >> split2
split2 = pourUntil (not . snd . head) source false' >>= split3
split3 Nothing = return ()
split3 (Just [~(_, False)]) = split0
in split0
endOf :: forall m x. (Monad m, MonoidNull x) => Splitter m x -> Splitter m x
endOf splitter = wrapMarkedSplitter splitter $
\source true false->
let false' = markDown false
split0 = pourUntil (snd . head) source false' >>= split1
split1 Nothing = return ()
split1 (Just [~(_, True)]) = split2
split2 = pourUntil (not . snd . head) source false'
>>= (putChunk true mempty >>) . split3
split3 Nothing = return ()
split3 (Just [~(_, False)]) = split0
in split0
followedBy :: forall m x. (Monad m, FactorialMonoid x) => PairBinder m -> Splitter m x -> Splitter m x -> Splitter m x
followedBy binder s1 s2 =
isolateSplitter $ \ source true false ->
pipeG binder
(transduce (splitterToMarker s1) source)
(\source'->
let false' = markDown false
get0 q = case Seq.viewl q
of Seq.EmptyL -> split0
(x, False) :< rest -> putChunk false x >> get0 rest
(_, True) :< _ -> get2 Seq.empty q
split0 = pourUntil (snd . head) source' false'
>>= maybe
(return ())
(const $ split1)
split1 = do (list, mx) <- getUntil (not . snd . head) source'
let list' = Seq.fromList $ List.map (\(x, True)-> x) list
maybe
(testEnd (Seq.fromList $ List.map (\(x, True)-> x) list))
((getPrime source' >>) . get3 list' . Seq.singleton . head)
mx
get2 q q' = case Seq.viewl q'
of Seq.EmptyL -> get source'
>>= maybe (testEnd q) (get2 q . Seq.singleton)
(x, True) :< rest -> get2 (q |> x) rest
(_, False) :< _ -> get3 q q'
get3 q q' = do let list = mconcat $ List.map fst (Foldable.toList $ Seq.viewl q')
(q'', mn) <- pipe (\sink-> putAll list sink >> get7 q' sink) (test q)
case mn of Nothing -> putQueue q false >> get0 q''
Just 0 -> get0 q''
Just n -> get8 True n q''
get7 q sink = do list <- getWhile (const True . head) source'
rest <- putAll (mconcat $ List.map (\(x, _)-> x) list) sink
let q' = q >< Seq.fromList list
if null rest
then get source' >>= maybe (return q') (\x-> get7 (q' |> x) sink)
else return q'
testEnd q = do ((), n) <- pipe (const $ return ()) (test q)
case n of Nothing -> putQueue q false >> return ()
_ -> return ()
test q source'' = liftM snd $
pipe
(transduce (splitterToMarker s2) source'')
(\source'''->
let test0 (x, False) = getPrime source'''
>> if null x then try0 else return Nothing
test0 (_, True) = test1
test1 = do putQueue q true
list <- getWhile (snd . head) source'''
let chunk = mconcat (List.map fst list)
putChunk true chunk
getPrime source'''
return (Just $ length chunk)
try0 = peek source''' >>= maybe (return Nothing) test0
in try0)
get8 False 0 q = get0 q
get8 True 0 q = get2 Seq.empty q
get8 _ n q | n > 0 =
case Seq.viewl q
of (x, False) :< rest | length x > n -> get0 ((drop n x, False) <| rest)
| otherwise -> get8 False (n length x) rest
(x, True) :< rest | length x > n -> get2 Seq.empty ((drop n x, True) <| rest)
| otherwise -> get8 True (n length x) rest
EmptyL -> error "Expecting a non-empty queue!"
in split0)
>> return ()
between :: forall m x. (Monad m, FactorialMonoid x) => PairBinder m -> Splitter m x -> Splitter m x -> Splitter m x
between binder s1 s2 = isolateSplitter $
\ source true false ->
pipeG binder
(transduce (splittersToPairMarker binder s1 s2) source)
(let pass n x = (if n > 0 then putChunk true x else putChunk false x)
>> return n
pass' n x = (if n >= 0 then putChunk true x else putChunk false x)
>> return n
state n (x, True, False) = pass (succ n) x
state n (x, False, True) = pass' (pred n) x
state n (x, True, True) = pass' n x
state n (x, False, False) = pass n x
in foldMStream_ state (0 :: Int))
>> return ()
wrapMarkedSplitter ::
forall m x. (Monad m, MonoidNull x) =>
Splitter m x
-> (forall a1 a2 a3 d. (AncestorFunctor a1 d, AncestorFunctor a2 d, AncestorFunctor a3 d,
AncestorFunctor a1 (SinkFunctor d [(x, Bool)]),
AncestorFunctor a2 (SourceFunctor d [(x, Bool)])) =>
Source m a1 [(x, Bool)] -> Sink m a2 x -> Sink m a3 x -> Coroutine d m ())
-> Splitter m x
wrapMarkedSplitter splitter splitMarked = isolateSplitter $
\ source true false ->
pipe
(transduce (splitterToMarker splitter) source)
(\source'-> splitMarked source' true false)
>> return ()
splitterToMarker :: forall m x. (Monad m, MonoidNull x) => Splitter m x -> Transducer m x [(x, Bool)]
splitterToMarker s = isolateTransducer mark
where mark :: forall d. Functor d => Source m d x -> Sink m d [(x, Bool)] -> Coroutine d m ()
mark source sink = split s source (markUpWith True sink) (markUpWith False sink)
parserToSplitter :: forall m x b. (Monad m, Monoid x) => Parser m x b -> Splitter m x
parserToSplitter t = isolateSplitter $ \ source true false ->
pipe
(transduce t source)
(\source->
pipe (\true'->
pipe (\false'->
let topLevel = pourWhile isContent source false'
>> get source
>>= maybe (return ()) (\x-> handleMarkup x >> topLevel)
handleMarkup (Markup p@Point{}) = putChunk true mempty >> return True
handleMarkup (Markup s@Start{}) = putChunk true mempty >> handleRegion >> return True
handleMarkup (Markup e@End{}) = putChunk false mempty >> return False
handleRegion = pourWhile isContent source true'
>> get source
>>= maybe (return ()) (\x -> handleMarkup x
>>= flip when handleRegion)
in topLevel)
(\src-> concatMapStream (\(Content x)-> x) src false))
(\src-> concatMapStream (\(Content x)-> x) src true))
>> return ()
where isContent [Markup{}] = False
isContent [Content{}] = True
fromContent (Content x) = x
splittersToPairMarker :: forall m x. (Monad m, FactorialMonoid x) => PairBinder m -> Splitter m x -> Splitter m x ->
Transducer m x [(x, Bool, Bool)]
splittersToPairMarker binder s1 s2 =
let synchronizeMarks :: forall a1 a2 d. (AncestorFunctor a1 d, AncestorFunctor a2 d) =>
Sink m a1 [(x, Bool, Bool)]
-> Source m a2 [((x, Bool), Bool)]
-> Coroutine d m (Maybe (Seq (x, Bool), Bool))
synchronizeMarks sink source = foldMStream handleMark Nothing source where
handleMark Nothing (p@(x, _), b) = return (Just (Seq.singleton p, b))
handleMark (Just (q, b)) mark@(p@(x, t), b')
| b == b' = return (Just (q |> p, b))
| otherwise = case Seq.viewl q
of Seq.EmptyL -> handleMark Nothing mark
(y, t') :< rest -> put sink (if b then (common, t', t) else (common, t, t'))
>> if lx == ly
then return (if Seq.null rest then Nothing else Just (rest, b))
else if lx < ly
then return (Just ((leftover, t') <| rest, b))
else handleMark (if Seq.null rest then Nothing
else Just (rest, b))
((leftover, t), b')
where lx = length x
ly = length y
(common, leftover) = if lx < ly then (x, drop lx y) else (y, drop ly x)
in isolateTransducer $
\source sink->
pipe
(\sync-> teeConsumers binder
(\source1-> transduce (splitterToMarker s1) source1 (mapSink (\x-> (x, True)) sync))
(\source2-> transduce (splitterToMarker s2) source2 (mapSink (\x-> (x, False)) sync))
source)
(synchronizeMarks sink)
>> return ()
zipSplittersWith :: forall m x. (Monad m, FactorialMonoid x) =>
(Bool -> Bool -> Bool) -> PairBinder m -> Splitter m x -> Splitter m x -> Splitter m x
zipSplittersWith f binder s1 s2
= isolateSplitter $ \ source true false ->
pipeG binder
(transduce (splittersToPairMarker binder s1 s2) source)
(mapMStream_ (\[(x, t1, t2)]-> if f t1 t2 then putChunk true x else putChunk false x))
>> return ()
groupMarks :: (Monad m, MonoidNull x, AncestorFunctor a d, AncestorFunctor a (SinkFunctor d x),
AncestorFunctor a (SinkFunctor (SinkFunctor d x) [(x, Bool)])) =>
Source m a [(x, Bool)] ->
(Bool -> Source m (SourceFunctor d x) x -> Coroutine (SourceFunctor d x) m r) ->
Coroutine d m ()
groupMarks source getConsumer = peek source >>= loop
where loop = maybe (return ()) ((>>= loop . fst) . startContent)
startContent (_, False) = pipe (next False) (getConsumer False)
startContent (_, True) = pipe (next True) (getConsumer True)
next t sink = liftM (fmap head) $
pourUntil ((\(_, t')-> t /= t') . head) source (markDown sink)
splitInput :: forall m a1 a2 a3 d x. (Monad m, Monoid x,
AncestorFunctor a1 d, AncestorFunctor a2 d, AncestorFunctor a3 d) =>
Splitter m x -> Source m a1 x -> Sink m a2 x -> Sink m a3 x -> Coroutine d m ()
splitInput splitter source true false = split splitter source true false
findsTrueIn :: forall m a d x. (Monad m, MonoidNull x, AncestorFunctor a d)
=> Splitter m x -> Source m a x -> Coroutine d m Bool
findsTrueIn splitter source = pipe
(\testTrue-> split splitter (liftSource source :: Source m d x)
testTrue
(nullSink :: Sink m d x))
(getRead readEof)
>>= \((), eof)-> return $ not eof
findsFalseIn :: forall m a d x. (Monad m, MonoidNull x, AncestorFunctor a d) =>
Splitter m x -> Source m a x -> Coroutine d m Bool
findsFalseIn splitter source = pipe
(\testFalse-> split splitter (liftSource source :: Source m d x)
(nullSink :: Sink m d x)
testFalse)
(getRead readEof)
>>= \((), eof)-> return $ not eof
readEof :: forall x. MonoidNull x => Reader x (Bool -> Bool) Bool
readEof x | null x = Deferred readEof True
| otherwise = Final x False
teeConsumers :: forall m a d x r1 r2. Monad m =>
PairBinder m
-> (forall a'. OpenConsumer m a' (SourceFunctor (SinkFunctor d x) x) x r1)
-> (forall a'. OpenConsumer m a' (SourceFunctor d x) x r2)
-> OpenConsumer m a d x (r1, r2)
teeConsumers binder c1 c2 source = pipeG binder consume1 c2
where consume1 sink = liftM snd $ pipe (tee source' sink) c1
source' :: Source m d x
source' = liftSource source
splitInputToConsumers :: forall m a d d1 x. (Monad m, Monoid x, d1 ~ SinkFunctor d x, AncestorFunctor a d) =>
PairBinder m -> Splitter m x -> Source m a x ->
(Source m (SourceFunctor d1 x) x -> Coroutine (SourceFunctor d1 x) m ()) ->
(Source m (SourceFunctor d x) x -> Coroutine (SourceFunctor d x) m ()) ->
Coroutine d m ()
splitInputToConsumers binder s source trueConsumer falseConsumer
= pipeG binder
(\false-> pipeG binder
(\true-> split s source' true false)
trueConsumer)
falseConsumer
>> return ()
where source' :: Source m d x
source' = liftSource source
putQueue :: forall m a d x. (Monad m, MonoidNull x, AncestorFunctor a d) => Seq x -> Sink m a x -> Coroutine d m x
putQueue q sink = putAll (mconcat $ Foldable.toList $ Seq.viewl q) sink