module Data.Machine.Group
( groupingOn
, taggedBy
, partitioning
, starve
, awaitUntil
)where
import Data.Machine
isLeft :: Either a b -> Bool
isLeft = either (const True) (const False)
groupingOn :: Monad m => (a -> a -> Bool) -> ProcessT m a b -> ProcessT m a b
groupingOn f m = taggedBy f ~> partitioning m
taggedBy :: Monad m => (a -> a -> Bool) -> ProcessT m a (Either () a)
taggedBy f = construct $ await >>= go
where go x = do
yield (Right x)
y <- await
if not (f x y) then yield (Left ()) >> go y else go y
partitioning :: Monad m => ProcessT m a b -> ProcessT m (Either () a) b
partitioning s = go s where
go m = MachineT $ runMachineT m >>= \v -> case v of
Stop -> runMachineT $ awaitUntil isLeft (const $ go s)
Yield o r -> return $ Yield o (go r)
Await f Refl r -> return $ Await g Refl (starve r $ encased Stop)
where
g (Right a) = go (f a)
g (Left ()) = starve r $ go s
awaitUntil :: Monad m => (a -> Bool) -> (a -> ProcessT m a b) -> ProcessT m a b
awaitUntil f cont = encased $ Await g Refl stopped
where g a = if f a then cont a else awaitUntil f cont