{-# LANGUAGE GADTs #-}
{-# LANGUAGE Rank2Types #-}
module Data.Machine.Tee
(
Tee, TeeT
, T(..)
, tee, teeT
, addL, addR
, capL, capR, capT
, zipWithT
, zipWith
, zipping
) where
import Data.Machine.Is
import Data.Machine.Plan
import Data.Machine.Process
import Data.Machine.Type
import Data.Machine.Source
import Prelude hiding ((.), id, zipWith)
data T a b c where
L :: T a b a
R :: T a b b
type Tee a b c = Machine (T a b) c
type TeeT m a b c = MachineT m (T a b) c
tee :: Monad m => ProcessT m a a' -> ProcessT m b b' -> TeeT m a' b' c -> TeeT m a b c
tee ma mb m = MachineT $ runMachineT m >>= \v -> case v of
Stop -> return Stop
Yield o k -> return $ Yield o $ tee ma mb k
Await f L ff -> runMachineT ma >>= \u -> case u of
Stop -> runMachineT $ tee stopped mb ff
Yield a k -> runMachineT $ tee k mb $ f a
Await g Refl fg ->
return $ Await (\a -> tee (g a) mb $ encased v) L $ tee fg mb $ encased v
Await f R ff -> runMachineT mb >>= \u -> case u of
Stop -> runMachineT $ tee ma stopped ff
Yield b k -> runMachineT $ tee ma k $ f b
Await g Refl fg ->
return $ Await (\b -> tee ma (g b) $ encased v) R $ tee ma fg $ encased v
teeT :: Monad m => TeeT m a b c -> MachineT m k a -> MachineT m k b -> MachineT m k c
teeT mt ma mb = MachineT $ runMachineT mt >>= \v -> case v of
Stop -> return Stop
Yield o k -> return $ Yield o $ teeT k ma mb
Await f L ff -> runMachineT ma >>= \u -> case u of
Stop -> runMachineT $ teeT ff stopped mb
Yield a k -> runMachineT $ teeT (f a) k mb
Await g rq fg ->
return $ Await (\r -> teeT (encased v) (g r) mb) rq $ teeT (encased v) fg mb
Await f R ff -> runMachineT mb >>= \u -> case u of
Stop -> runMachineT $ teeT ff ma stopped
Yield a k -> runMachineT $ teeT (f a) ma k
Await g rq fg ->
return $ Await (\r -> teeT (encased v) ma (g r)) rq $ teeT (encased v) ma fg
addL :: Monad m => ProcessT m a b -> TeeT m b c d -> TeeT m a c d
addL p = tee p echo
{-# INLINE addL #-}
addR :: Monad m => ProcessT m b c -> TeeT m a c d -> TeeT m a b d
addR = tee echo
{-# INLINE addR #-}
capL :: Monad m => SourceT m a -> TeeT m a b c -> ProcessT m b c
capL s t = fit cappedT $ addL s t
{-# INLINE capL #-}
capR :: Monad m => SourceT m b -> TeeT m a b c -> ProcessT m a c
capR s t = fit cappedT $ addR s t
{-# INLINE capR #-}
capT :: Monad m => SourceT m a -> SourceT m b -> TeeT m a b c -> SourceT m c
capT l r t = plug $ tee l r t
{-# INLINE capT #-}
cappedT :: T a a b -> Is a b
cappedT R = Refl
cappedT L = Refl
{-# INLINE cappedT #-}
zipWithT :: (a -> b -> c) -> PlanT (T a b) c m ()
zipWithT f = do { a <- awaits L; b <- awaits R; yield $ f a b }
{-# INLINE zipWithT #-}
zipWith :: (a -> b -> c) -> Tee a b c
zipWith f = repeatedly $ do
a <- awaits L
b <- awaits R
yield (f a b)
{-# INLINE zipWith #-}
zipping :: Tee a b (a, b)
zipping = zipWith (,)
{-# INLINE zipping #-}