-- | -- Module: Control.Wire.Prefab.Event -- Copyright: (c) 2012 Ertugrul Soeylemez -- License: BSD3 -- Maintainer: Ertugrul Soeylemez <es@ertes.de> -- -- Event wires. module Control.Wire.Prefab.Event ( -- * Instants afterI, eventsI, forI, notYet, once, periodicallyI, -- * Signal analysis changed, inject, -- ** Predicate-based asSoonAs, edge, forbid, require, unless, until, when, while, -- * Time after, events, for, periodically, -- * Utilities inhibit ) where import Control.Category import Control.Wire.Classes import Control.Wire.Types import Control.Wire.Wire import Data.Monoid import Prelude hiding ((.), id, until) -- | Produce after the given amount of time. -- -- * Depends: current instant when producing, time. -- -- * Inhibits: until the given amount of time has passed. after :: (Monoid e) => Time -> Event e m a after t | t <= 0 = identity | otherwise = mkPure $ \dt _ -> (Left mempty, after (t - dt)) -- | Produce after the given number of instants. -- -- * Depends: current instant when producing. -- -- * Inhibits: until the given number of instants has passed. afterI :: (Monoid e) => Int -> Event e m a afterI t | t <= 0 = identity | otherwise = mkPure $ \_ _ -> (Left mempty, afterI (t - 1)) -- | Inhibit until the given predicate holds for the input signal. Then -- produce forever. -- -- * Depends: current instant, if the predicate is strict. Once true, -- on current instant forever. -- -- * Inhibits: until the predicate becomes true. asSoonAs :: (Monoid e) => (a -> Bool) -> Event e m a asSoonAs p = mkPure $ \_ x -> if p x then (Right x, identity) else (Left mempty, asSoonAs p) -- | Produce when the signal has changed and at the first instant. -- -- * Depends: current instant. -- -- * Inhibits: after the first instant when the input has changed. changed :: (Eq a, Monoid e) => Event e m a changed = mkPure $ \_ x0 -> (Right x0, changed' x0) where changed' x' = mkPure $ \_ x -> (if x' == x then Left mempty else Right x, changed' x) -- | Produces once whenever the given predicate switches from 'False' to -- 'True'. -- -- * Depends: current instant. -- -- * Inhibits: when the predicate has not just switched from 'False' to -- 'True'. edge :: (Monoid e) => (a -> Bool) -> Event e m a edge p = off where off = mkPure $ \_ x -> if p x then (Right x, on) else (Left mempty, off) on = mkPure $ \_ x -> (Left mempty, if p x then on else off) -- | Produce once periodically. The production periods are given by the -- argument list. When it's @[1,2,3]@ it produces after one second, -- then after two more seconds and finally after three more seconds. -- When the list is exhausted, it never produces again. -- -- * Depends: current instant when producing, time. -- -- * Inhibits: between the given intervals. events :: (Monoid e) => [Time] -> Event e m a events [] = never events (t':ts) = mkPure $ \dt x -> let t = t' - dt in if t <= 0 then (Right x, events (mapHead (+ t) ts)) else (Left mempty, events (t:ts)) where mapHead :: (a -> a) -> [a] -> [a] mapHead _ [] = [] mapHead f (x:xs) = f x : xs -- | Variant of 'periodically' in number of instants instead of amount -- of time. -- -- * Depends: current instant when producing. -- -- * Inhibits: between the given intervals. eventsI :: (Monoid e) => [Int] -> Event e m a eventsI [] = never eventsI (0:ts) = mkPure $ \_ x -> (Right x, eventsI ts) eventsI (t:ts) = mkPure $ \_ _ -> (Left mempty, eventsI (t - 1 : ts)) -- | Produce for the given amount of time. -- -- * Depends: current instant when producing, time. -- -- * Inhibits: after the given amount of time has passed. for :: (Monoid e) => Time -> Event e m a for t | t <= 0 = never | otherwise = mkPure $ \dt x -> (Right x, for (t - dt)) -- | Same as 'unless'. forbid :: (Monoid e) => (a -> Bool) -> Event e m a forbid = unless -- | Produce for the given number of instants. -- -- * Depends: current instant when producing. -- -- * Inhibits: after the given number of instants has passed. forI :: (Monoid e) => Int -> Event e m a forI t | t <= 0 = never | otherwise = mkPure $ \_ x -> (Right x, forI (t - 1)) -- | Inhibit with the given value. You may want to use a combination of -- 'Control.Applicative.empty' and 'Control.Wire.Trans.Event.<!>' -- instead. -- -- * Inhibits: always. inhibit :: e -> Wire e m a b inhibit ex = mkFix (\_ _ -> Left ex) -- | Inject the input signal. Please keep in mind that in application -- code it is almost always wrong to use this wire. It should only be -- used to interact with other frameworks/abstractions, and even then -- it's probably just a last resort. -- -- When you want to write your own wires, consider using 'mkPure' or the -- various variants of it. -- -- * Depends: current instant. -- -- * Inhibits: depending on input signal (see 'Injectable'). inject :: (Injectable e f) => Wire e m (f b) b inject = mkFix (const toSignal) -- | Inhibit once. -- -- * Depends: current instant after the first instant. -- -- * Inhibits: in the first instant. notYet :: (Monoid e) => Event e m a notYet = mkPure $ \_ _ -> (Left mempty, identity) -- | Produce once. -- -- * Depends: current instant in the first instant. -- -- * Inhibits: after the first instant. once :: (Monoid e) => Event e m a once = mkPure $ \_ x -> (Right x, never) -- | Produce once periodically with the given time interval. -- -- * Depends: current instant when producing, time. -- -- * Inhibits: between the intervals. periodically :: (Monoid e) => Time -> Event e m a periodically = events . repeat -- | Produce once periodically with the given number of instants as the -- interval. -- -- * Depends: current instant when producing. -- -- * Inhibits: between the intervals. periodicallyI :: (Monoid e) => Int -> Event e m a periodicallyI = eventsI . repeat -- | Same as 'when'. require :: (Monoid e) => (a -> Bool) -> Event e m a require = when -- | Produce when the given predicate on the input signal does not hold. -- -- * Depends: current instant if the predicate is strict. -- -- * Inhibits: When the predicate is true. unless :: (Monoid e) => (a -> Bool) -> Event e m a unless p = mkFix $ \_ x -> if p x then Left mempty else Right x -- | Produce until the given predicate on the input signal holds, then -- inhibit forever. -- -- * Depends: current instant, if the predicate is strict. -- -- * Inhibits: forever as soon as the predicate becomes true. until :: (Monoid e) => (a -> Bool) -> Event e m a until p = while (not . p) -- | Produce when the given predicate on the input signal holds. -- -- * Depends: current instant if the predicate is strict. -- -- * Inhibits: When the predicate is false. when :: (Monoid e) => (a -> Bool) -> Event e m a when p = mkFix $ \_ x -> if p x then Right x else Left mempty -- | Produce while the given predicate on the input signal holds, then -- inhibit forever. -- -- * Depends: current instant, if the predicate is strict. -- -- * Inhibits: forever as soon as the predicate becomes false. while :: (Monoid e) => (a -> Bool) -> Event e m a while p = mkPure $ \_ x -> if p x then (Right x, while p) else (Left mempty, never)