{-# LANGUAGE Safe #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE Arrows #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE TypeSynonymInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} module Control.Arrow.Machine.Misc.Pump ( -- *Pump -- | This module should be imported manually. -- -- `intake` records events and `outlet` emits recorded events. -- -- Tipically they are used with rec statement. -- -- `clock` arguments are needed to drive a `Pump`. -- For a pair of `intake` and `outlet`, `clock` arguments must point the -- same event stream. Duct(), intake, outlet ) where import Prelude hiding (id, (.)) import Data.Functor ((<$), (<$>)) import Control.Category import Control.Arrow import qualified Control.Arrow.Machine as P import Data.Monoid (Endo(Endo), mappend, appEndo) newtype Duct a = Duct (Endo [a]) oneMore :: Monad m => P.ProcessT m (P.Event ()) (P.Event ()) oneMore = proc ev -> do ed <- P.onEnd -< ev P.gather -< [ev, ed] intake :: Monad m => P.ProcessT m (P.Event b, P.Event ()) (Duct b) intake = proc (ev, clock) -> do cl2 <- oneMore -< clock append <- returnA -< (\x y -> y `mappend` Endo (x:)) <$> ev e <- P.dAccum (Endo id) <<< P.gather -< [ (const $ Endo id) <$ cl2, append ] returnA -< Duct e outlet :: Monad m => P.ProcessT m (Duct b, P.Event ()) (P.Event b) outlet = proc (~(Duct dct), clock) -> do cl2 <- oneMore -< clock P.fork -< appEndo dct [] <$ cl2