module Data.Machine.Wye
(
Wye, WyeT
, Y(..)
, wye
, addX, addY
, capX, capY, capWye
) where
import Control.Category
import Data.Machine.Process
import Data.Machine.Type
import Data.Machine.Is
import Data.Machine.Source
import Prelude hiding ((.),id)
data Y a b c where
X :: Y a b a
Y :: Y a b b
Z :: Y a b (Either a b)
type Wye a b c = Machine (Y a b) c
type WyeT m a b c = MachineT m (Y a b) c
wye :: Monad m => ProcessT m a a' -> ProcessT m b b' -> WyeT m a' b' c -> WyeT m a b c
wye ma mb m = MachineT $ runMachineT m >>= \v -> case v of
Yield o k -> return $ Yield o (wye ma mb k)
Stop -> return Stop
Await f X ff -> runMachineT ma >>= \u -> case u of
Yield a k -> runMachineT . wye k mb $ f a
Stop -> runMachineT $ wye stopped mb ff
Await g Refl fg -> return . Await (\a -> wye (g a) mb $ encased v) X
. wye fg mb $ encased v
Await f Y ff -> runMachineT mb >>= \u -> case u of
Yield b k -> runMachineT . wye ma k $ f b
Stop -> runMachineT $ wye ma stopped ff
Await g Refl fg -> return . Await (\b -> wye ma (g b) $ encased v) Y
. wye ma fg $ encased v
Await f Z ff -> runMachineT ma >>= \u -> case u of
Yield a k -> runMachineT . wye k mb . f $ Left a
Stop -> runMachineT mb >>= \w -> case w of
Yield b k -> runMachineT . wye stopped k . f $ Right b
Stop -> runMachineT $ wye stopped stopped ff
Await g Refl fg -> return . Await (\b -> wye stopped (g b) $ encased v) Y
. wye stopped fg $ encased v
Await g Refl fg -> runMachineT mb >>= \w -> case w of
Yield b k -> runMachineT . wye (encased u) k . f $ Right b
Stop -> return . Await (\a -> wye (g a) stopped $ encased v) X
. wye fg stopped $ encased v
Await h Refl fh -> return . Await (\c -> case c of
Left a -> wye (g a) (encased w) $ encased v
Right b -> wye (encased u) (h b) $ encased v) Z
. wye fg fh $ encased v
addX :: Monad m => ProcessT m a b -> WyeT m b c d -> WyeT m a c d
addX p = wye p echo
addY :: Monad m => ProcessT m b c -> WyeT m a c d -> WyeT m a b d
addY = wye echo
capX :: Monad m => SourceT m a -> WyeT m a b c -> ProcessT m b c
capX s t = process (capped Right) (addX s t)
capY :: Monad m => SourceT m b -> WyeT m a b c -> ProcessT m a c
capY s t = process (capped Left) (addY s t)
capWye :: Monad m => SourceT m a -> SourceT m b -> WyeT m a b c -> SourceT m c
capWye a b = plug . wye a b
capped :: (a -> Either a a) -> Y a a b -> a -> b
capped _ X = id
capped _ Y = id
capped f Z = f