module Ros.Topic where
#if __GLASGOW_HASKELL__ >= 710
import Prelude hiding (join)
#endif
import Control.Applicative
import Control.Arrow ((***), second)
import Control.Monad ((<=<), (>=>))
import Control.Monad.IO.Class
newtype Topic m a = Topic { runTopic :: m (a, Topic m a) }
instance Functor m => Functor (Topic m) where
fmap f (Topic ma) = Topic $ fmap (f *** fmap f) ma
instance Applicative m => Applicative (Topic m) where
pure x = let t = Topic $ pure (x, t) in t
Topic ma <*> Topic mb = Topic $ uncurry (***) . (($) *** (<*>)) <$> ma <*> mb
head :: Functor m => Topic m a -> m a
head = fmap fst . runTopic
uncons :: Topic m a -> m (a, Topic m a)
uncons = runTopic
force :: Monad m => Topic m a -> m (Topic m a)
force = uncons >=> return . Topic . return
cons :: Monad m => a -> Topic m a -> Topic m a
cons x t = Topic $ return (x, t)
tail :: Monad m => Topic m a -> Topic m a
tail = Topic . (runTopic . snd <=< runTopic)
tails :: Monad m => Topic m a -> Topic m (Topic m a)
tails t = Topic $ do (x,t') <- runTopic t
return (Topic $ return (x,t'), tails t')
filter :: Monad m => (a -> Bool) -> Topic m a -> Topic m a
filter p = metamorph go
where go x | p x = yield x go
| otherwise = skip go
take :: Monad m => Int -> Topic m a -> m [a]
take = aux []
where aux acc 0 _ = return (reverse acc)
aux acc n' t = do (x, t') <- runTopic t
aux (x:acc) (n'1) t'
take_ :: Monad m => Int -> Topic m a -> m ()
take_ 0 = const $ return ()
take_ n = take_ (n1) . snd <=< runTopic
drop :: Monad m => Int -> Topic m a -> Topic m a
drop = (Topic .) . aux
where aux 0 = runTopic
aux n = aux (n1) . snd <=< runTopic
dropWhile :: Monad m => (a -> Bool) -> Topic m a -> Topic m a
dropWhile p = Topic . go
where go = check <=< runTopic
check (x,t) | p x = go t
| otherwise = return (x, t)
takeWhile :: Monad m => (a -> Bool) -> Topic m a -> m [a]
takeWhile p = go []
where go acc t = do (x,t') <- runTopic t
if p x then go (x:acc) t'
else return . reverse $ x:acc
break :: Monad m => (a -> Bool) -> Topic m a -> m ([a], Topic m a)
break p = go []
where go acc = check acc <=< runTopic
check acc (x,t)
| p x = go (x:acc) t
| otherwise = return (reverse (x:acc), t)
splitAt :: Monad m => Int -> Topic m a -> m ([a], Topic m a)
splitAt = go []
where go acc 0 t = return (reverse acc, t)
go acc n t = do (x,t') <- runTopic t
go (x:acc) (n1) t'
catMaybes :: Monad m => Topic m (Maybe a) -> Topic m a
catMaybes = metamorph go
where go = maybe (skip go) (flip yield go)
repeatM :: Monad m => m a -> Topic m a
repeatM action = go
where go = Topic $ action >>= \x -> return (x, go)
unfold :: Functor m => (b -> m (a,b)) -> b -> Topic m a
unfold f z0 = go z0
where go z = Topic $ second go <$> f z
newtype IterCont a b = IterCont (Maybe b, a -> IterCont a b)
instance Functor (IterCont a) where
fmap f (IterCont (x, k)) = IterCont (fmap f x, fmap f . k)
newtype IterContM m a b = IterContM (Maybe b, a -> m (IterContM m a b))
instance Monad m => Functor (IterContM m a) where
fmap f (IterContM (x, k)) = IterContM (fmap f x, return . fmap f <=< k)
yield :: b -> (a -> IterCont a b) -> IterCont a b
yield = curry IterCont . Just
skip :: (a -> IterCont a b) -> IterCont a b
skip = curry IterCont Nothing
yieldM :: Monad m => b -> (a -> m (IterContM m a b)) -> m (IterContM m a b)
yieldM = (return .) . curry IterContM . Just
skipM :: Monad m => (a -> m (IterContM m a b)) -> m (IterContM m a b)
skipM = return . curry IterContM Nothing
metamorph :: Monad m => (a -> IterCont a b) -> Topic m a -> Topic m b
metamorph f t = Topic $ do (x,t') <- runTopic t
let IterCont (x', f') = f x
case x' of
Nothing -> runTopic $ metamorph f' t'
Just x'' -> return (x'', metamorph f' t')
metamorphM :: Monad m => (a -> m (IterContM m a b)) -> Topic m a -> Topic m b
metamorphM f t = Topic $ do (x,t') <- runTopic t
IterContM (x', f') <- f x
case x' of
Nothing -> runTopic $ metamorphM f' t'
Just x'' -> return (x'', metamorphM f' t')
bimetamorph :: Monad m =>
(a -> IterCont a b) -> (a -> IterCont a b) ->
Topic m a -> Topic m b
bimetamorph f g t = Topic $ do (x,t') <- runTopic t
let IterCont (y, f') = f x
IterCont (z, g') = g x
aux y . aux z . runTopic $ bimetamorph f' g' t'
where aux = maybe id (\x y -> return (x, Topic y))
bimetamorphM :: Monad m =>
(a -> m (IterContM m a b)) -> (a -> m (IterContM m a b)) ->
Topic m a -> Topic m b
bimetamorphM f g t = Topic $ do (x,t') <- runTopic t
IterContM (y, f') <- f x
IterContM (z, g') <- g x
aux y . aux z . runTopic $ bimetamorphM f' g' t'
where aux = maybe id (\x y -> return (x, Topic y))
bimetamorphE :: Monad m =>
(a -> IterCont a b) -> (a -> IterCont a c) ->
Topic m a -> Topic m (Either b c)
bimetamorphE f g t = bimetamorph (fmap Left . f) (fmap Right . g) t
bimetamorphME :: Monad m =>
(a -> m (IterContM m a b)) -> (a -> m (IterContM m a c)) ->
Topic m a -> Topic m (Either b c)
bimetamorphME f g t =
bimetamorphM (return . fmap Left <=< f) (return . fmap Right <=< g) t
join :: (Functor m, Monad m) => Topic m (m a) -> Topic m a
join t = Topic $ do (x, t') <- runTopic t
x' <- x
return (x', join t')
forever :: Monad m => Topic m a -> m b
forever = forever . snd <=< runTopic
mapM :: (Functor m, Monad m) => (a -> m b) -> Topic m a -> Topic m b
mapM = (join .) . fmap
mapM_ :: Monad m => (a -> m ()) -> Topic m a -> m ()
mapM_ f = go
where go = uncurry (>>) . (f *** go) <=< runTopic
scan :: Monad m => (a -> b -> a) -> a -> Topic m b -> Topic m a
scan f z = metamorph (go z)
where go acc x = let x' = f acc x in yield x' (go x')
showTopic :: (MonadIO m, Functor m, Show a) => Topic m a -> Topic m ()
showTopic = join . fmap (liftIO . putStrLn . show)