module Tubes.Util
( cat
, Tubes.Util.map
, Tubes.Util.drop
, Tubes.Util.take
, Tubes.Util.takeWhile
, Tubes.Util.filter
, Tubes.Util.reduce
, Tubes.Util.every
, Tubes.Util.prompt
, Tubes.Util.display
, Tubes.Util.unyield
, Tubes.Util.mapM
, Tubes.Util.sequence
) where
import Prelude hiding (map, mapM)
import Control.Monad (forever, unless, replicateM_, when)
import Control.Monad.Trans
import Control.Monad.Trans.Free
import Control.Monad.IO.Class
import Data.Foldable
import Data.Monoid (Monoid, mappend, mempty)
import System.IO
import Tubes.Core
fix :: (a -> a) -> a
fix f = let x = f x in x
diverge :: a
diverge = fix id
cat :: Monad m => Tube a a m r
cat = forever $ do
x <- await
yield x
map :: (Monad m) => (a -> b) -> Tube a b m r
map f = for cat $ \x -> yield (f x)
drop :: Monad m => Int -> Tube a a m r
drop n = do
replicateM_ n await
cat
filter :: Monad m => (a -> Bool) -> Tube a a m r
filter pred = for cat $ \x -> when (pred x) (yield x)
takeWhile :: Monad m => (a -> Bool) -> Tube a a m ()
takeWhile pred = go
where
go = do
a <- await
if (pred a)
then do
yield a
go
else return ()
take :: Monad m => Int -> Tube a a m ()
take n = do
replicateM_ n $ do
x <- await
yield x
unyield :: Monad m => FreeT (TubeF x b) m () -> m (Maybe (b, FreeT (TubeF x b) m ()))
unyield tsk = do
tsk' <- runFreeT tsk
case tsk' of
Pure _ -> return Nothing
Free tsk'' -> do
let res = runT tsk'' diverge (\(v, k) -> Just (v, k))
return res
reduce :: Monad m
=> (x -> a -> x)
-> x
-> (x -> b)
-> Source a m ()
-> m b
reduce step begin done p0 = runFreeT p0 >>= \p' -> loop p' begin where
loop (Pure _) x = return (done x)
loop (Free p) x = runT p diverge (\(v, k) ->
runFreeT k >>= \k' -> loop k' $! step x v)
every :: (Foldable t, Monad m) => t b -> Tube a (Maybe b) m ()
every xs = (each xs >< map Just) >> yield Nothing
mapM :: Monad m => (a -> m b) -> Tube a b m r
mapM f = for cat $ \a -> do
b <- lift $ f a
yield b
sequence :: Monad m => Tube (m a) a m r
sequence = mapM id
prompt :: MonadIO m => Source String m ()
prompt = do
liftIO . putStr $ "> "
eof <- liftIO isEOF
unless eof $ do
str <- liftIO getLine
yield str
prompt
display :: MonadIO m => Sink String m ()
display = forever $ do
it <- await
liftIO . putStrLn $ it