-- | -- Module: Control.Wire.Trans.Event -- Copyright: (c) 2012 Ertugrul Soeylemez -- License: BSD3 -- Maintainer: Ertugrul Soeylemez -- -- Event-related wire combinators. module Control.Wire.Trans.Event ( -- * Combinators eitherE, (<||>), -- * Holding events hold, hold_, holdFor, holdForI, -- * Inhibition (), event, exhibit, gotEvent, notE ) where import Control.Arrow import Control.Category import Control.Wire.Types import Control.Wire.Wire import Data.Monoid hiding ((<>)) import Data.Semigroup import Prelude hiding ((.), id) -- | Try both wires combining their results with the given functions. -- -- * Like argument wires. -- -- * Inhibits: when both wires inhibit. eitherE :: (Monad m, Monoid e) => (b1 -> b) -- ^ Only left. -> (b2 -> b) -- ^ Only right. -> (b1 -> b2 -> b) -- ^ Both. -> Wire e m a b1 -- ^ First wire. -> Wire e m a b2 -- ^ Second wire. -> Wire e m a b eitherE left right both = eitherE' where eitherE' w1' w2' = mkGen $ \dt x' -> do (mx1, w1) <- stepWire w1' dt x' (mx2, w2) <- stepWire w2' dt x' let res = case (mx1, mx2) of (Left ex1, Left ex2) -> Left (mappend ex1 ex2) (Right x1, Right x2) -> Right (both x1 x2) (Right x1, _) -> Right (left x1) (_, Right x2) -> Right (right x2) return (res, eitherE' w1 w2) -- | Semigroup version of 'eitherE'. (<||>) :: (Monad m, Monoid e, Semigroup b) => Wire e m a b -> Wire e m a b -> Wire e m a b (<||>) = eitherE id id (<>) -- | If the argument wire inhibits, inhibit with the given exception -- instead. -- -- * Depends: like argument wire. -- -- * Inhibits: like argument wire. () :: (Monad m) => Wire e m a b -> e -> Wire e m a b w ex = mapOutput (either (Left . const ex) Right) w -- | Prevent a wire from inhibiting. Instead produce a signal wrapped -- in 'Maybe'. -- -- Note: You probably shouldn't use this function. -- -- * Depends: like argument wire. event :: (Monad m) => Wire e m a b -> Wire e m a (Maybe b) event = mapOutput (Right . either (const Nothing) Just) -- | Prevent a wire from inhibiting. Instead produce the inhibition -- value. -- -- Note: You probably shouldn't use this function. -- -- * Depends: like argument wire. exhibit :: (Monad m) => Wire e m a b -> Wire e m a (Either e b) exhibit = mapOutput Right -- | Prevent a wire from inhibiting. Instead produce 'False', if the -- wire inhibited. -- -- Note: You probably shouldn't use this function. -- -- * Depends: like argument wire. gotEvent :: (Monad m) => Wire e m a b -> Wire e m a Bool gotEvent = mapOutput (Right . either (const False) (const True)) -- | Hold the latest event. Produces the last produced value starting -- with the given one. -- -- * Depends: like argument wire. hold :: (Monad m) => b -> Wire e m a b -> Wire e m a b hold x0 w' = mkGen $ \dt x' -> do (mx, w) <- stepWire w' dt x' case mx of Left _ -> return (Right x0, hold x0 w) Right x -> return (Right x, hold x w) -- | Hold the event. Once the argument wire produces the produced value -- is held until the argument wire produces again. -- -- * Depends: like argument wire. -- -- * Inhibits: until the argument wire produces for the first time. hold_ :: (Monad m) => Wire e m a b -> Wire e m a b hold_ w' = mkGen $ \dt x' -> do (mx, w) <- stepWire w' dt x' return (mx, either (const hold_) hold mx w) -- | Hold the event for the given amount of time. When the argument -- wire produces, the produced value is kept for the given amount of -- time. If the wire produces again while another value is kept, the -- new value takes precedence. -- -- * Depends: like argument wire. -- -- * Inhibits: as described. holdFor :: (Monad m) => Time -> Wire e m a b -> Wire e m a b holdFor t0 w = hold' . exhibit w where hold' = mkPure $ \_ mx -> case mx of Left _ -> (mx, hold') Right x -> (mx, hold'' t0 x) hold'' t' x' = mkPure $ \dt mx -> let t = t' - dt in case mx of Left _ | t > 0 -> (Right x', hold'' t x') | otherwise -> (mx, hold') Right x -> (mx, hold'' t0 x) -- | Hold the event for the given number of instances. When the -- argument wire produces, the produced value is kept for the given -- number of instances. If the wire produces again while another value -- is kept, the new value takes precedence. -- -- * Depends: like argument wire. -- -- * Inhibits: as described. holdForI :: (Monad m) => Time -> Wire e m a b -> Wire e m a b holdForI t0 w = hold' . exhibit w where hold' = mkPure $ \_ -> id &&& either (const hold') (hold'' t0) hold'' t x' | t <= 0 = hold' | otherwise = mkPure $ \_ mx -> case mx of Left _ -> (Right x', hold'' (t - 1) x') Right x -> (mx, hold'' t0 x) -- | Act like the identity wire, if the argument wire inhibits. -- Inhibit, if the argument wire produces. -- -- * Depends: like argument wire. -- -- * Inhibits: when argument wire produces. notE :: (Monad m, Monoid e) => Event e m a -> Event e m a notE w' = mkGen $ \dt x' -> do (mx, w) <- stepWire w' dt x' return (either (const $ Right x') (const $ Left mempty) mx, notE w)