-- |-- Module: Control.Wire.Prefab.Event-- Copyright: (c) 2011 Ertugrul Soeylemez-- License: BSD3-- Maintainer: Ertugrul Soeylemez <es@ertes.de>---- Wires for generating and manipulating events.moduleControl.Wire.Prefab.Event(-- * Event generation-- ** TimedWAfter(..),WAt(..),WDelayEvents(..),WPeriodically(..),-- ** Unconditional inhibitioninhibit,never,-- ** Predicate-basedasSoonAs,edge,require,forbid,while,-- ** Instant-basednotYet,once)whereimportqualifiedData.MapasMimportqualifiedData.SequenceasSimportControl.ArrowimportControl.Monad.FiximportControl.Wire.ClassesimportControl.Wire.Prefab.SimpleimportControl.Wire.TypesimportData.MonoidimportData.Map(Map)importData.Sequence(Seq,ViewL(..),(><))importData.VectorSpace-- | Produces once after the input time interval has passed.---- * Depends: Current instant.---- * Inhibits: Always except at the target instant.classArrow(>~)=>WAftert(>~)|(>~)->twhereafter::Monoide=>Wiree(>~)t()instance(AdditiveGroupt,MonadClocktm,Ordt)=>WAftert(Kleislim)whereafter=after0whereafter0::foralle.Monoide=>Wiree(Kleislim)t()after0=WmGen$\int->dot0<-getTimereturn(int<=zeroV`orGoWith`after't0)whereafter'::t->Wiree(Kleislim)t()after't0=fix$\again->WmGen$\int->dot<-getTimereturn(t^-^t0>=int`orGoWith`again)-- | Produces once as soon as the current global time is later than or-- equal to the input global time and never again.---- * Depends: Current instant.---- * Inhibits: Always except at the target instant.classArrow(>~)=>WAtt(>~)|(>~)->twhereat::Monoide=>Wiree(>~)t()instance(MonadClocktm,Ordt)=>WAtt(Kleislim)whereat=WmGen$\tt->dot<-getTimereturn(t>=tt`orGoWith`at)-- | Delay incoming events.classArrow(>~)=>WDelayEventst(>~)|(>~)->twhere-- | Delays each incoming event (left signal) by the given time-- delta (right signal). The time delta at the instant the event-- happened is significant.---- * Depends: Current instant.---- * Inhibits: When no delayed event happened.delayEvents::Monoide=>Wiree(>~)([b],t)b-- | Delays each incoming event (left signal) by the given time-- delta (middle signal). The time delta at the instant the event-- happened is significant. The right signal gives a maximum number-- of events queued. When exceeded, new events are dropped, until-- there is enough room.---- * Depends: Current instant.---- * Inhibits: When no delayed event happened.delayEventsSafe::Monoide=>Wiree(>~)(([b],t),Int)binstance(AdditiveGroupt,MonadClocktm,Ordt)=>WDelayEventst(Kleislim)where-- delayEventsdelayEvents=delayEvents'M.emptywheredelayEvents'::Monoide=>Mapt(Seqb)->Wiree(Kleislim)([b],t)bdelayEvents'delayed'=WmGen$\(evs,int)->dot<-getTimeletdelayed=M.insertWith'(><)(t^+^int)(S.fromListevs)delayed'return$caseM.minViewWithKeydelayedofNothing->(Leftmempty,delayEvents'delayed)Just((tt,revs),restMap)|tt>t->(Leftmempty,delayEvents'delayed)|otherwise->caseS.viewlrevsofEmptyL->(Leftmempty,delayEvents'restMap)rev:<restEvs->(Rightrev,delayEvents'(ifS.nullrestEvsthenrestMapelseM.insertttrestEvsrestMap))-- delayEventsSafedelayEventsSafe=delayEvents'0M.emptywheredelayEvents'::Monoide=>Int->Mapt(Seqb)->Wiree(Kleislim)(([b],t),Int)bdelayEvents'curNum'delayed'=WmGen$\((evs,int),maxNum)->dot<-getTimeletaddSeq=S.fromListevs(curNum,delayed)=ifnullevs||curNum'>=maxNumthen(curNum',delayed')else(curNum'+S.lengthaddSeq,M.insertWith'(><)(t^+^int)addSeqdelayed')return$caseM.minViewWithKeydelayedofNothing->(Leftmempty,delayEvents'curNumdelayed)Just((tt,revs),restMap)|tt>t->(Leftmempty,delayEvents'curNumdelayed)|otherwise->caseS.viewlrevsofEmptyL->(Leftmempty,delayEvents'curNumrestMap)rev:<restEvs->(Rightrev,delayEvents'(predcurNum)(ifS.nullrestEvsthenrestMapelseM.insertttrestEvsrestMap))-- | Inhibits as long as the input signal is 'False'. Once it switches-- to 'True', it produces forever.---- * Depends: Current instant.---- * Inhibits: As long as input signal is 'False', then never again.asSoonAs::(Monoide,WirePure(>~))=>Wiree(>~)Bool()asSoonAs=mkPure$\b->ifbthen(Right(),constant())else(Leftmempty,asSoonAs)-- | Produces once whenever the input signal switches from 'False' to-- 'True'.---- * Depends: Current instant.---- * Inhibits: Always except at the above mentioned instants.edge::foralle(>~).(Monoide,WirePure(>~))=>Wiree(>~)Bool()edge=mkPure$\b->ifbthen(Right(),switchBack)else(Leftmempty,edge)whereswitchBack::Wiree(>~)Bool()switchBack=mkPure$\b->(Leftmempty,ifbthenswitchBackelseedge)-- | Produces, whenever the current input signal is 'False'.---- * Depends: Current instant.---- * Inhibits: When input is 'True'.forbid::(Monoide,WirePure(>~))=>Wiree(>~)Bool()forbid=mkPureFix(\b->ifbthenLeftmemptyelseRight())-- | Never produces. Always inhibits with the current input signal.---- * Depends: Current instant.---- * Inhibits: Always.inhibit::WirePure(>~)=>Wiree(>~)ebinhibit=mkPureFixLeft-- | Never produces. Equivalent to 'zeroArrow'.---- * Inhibits: Always.never::(Monoide,WirePure(>~))=>Wiree(>~)abnever=mkPureFix(const(Leftmempty))-- | Inhibit at the first instant. Then produce forever.---- * Inhibits: At the first instant.notYet::(Monoide,WirePure(>~))=>Wiree(>~)bbnotYet=mkPure(const(Leftmempty,identity))-- | Acts like the identity function once and never again.---- * Inhibits: After the first instant.once::(Monoide,WirePure(>~))=>Wiree(>~)bbonce=mkPure$\x->(Rightx,never)-- | Periodically produces an event. The period is given by the input-- time delta and can change over time. The current time delta with-- respect to the last production is significant. Does not produce at-- the first instant, unless the first delta is nonpositive.---- * Depends: Current instant.---- * Inhibits: Always except at the periodic ticks.classArrow(>~)=>WPeriodicallyt(>~)|(>~)->twhereperiodically::Monoide=>Wiree(>~)t()instance(AdditiveGroupt,MonadClocktm,Ordt)=>WPeriodicallyt(Kleislim)whereperiodically=WmGen$\int->ifint<=zeroVthenreturn(Right(),periodically)elsedot<-getTimereturn(Leftmempty,periodically't)whereperiodically'::Monoide=>t->Wiree(Kleislim)t()periodically't0=WmGen$\int->dot<-getTimelettt=t0^+^intreturn$ift>=ttthen(Right(),periodically'tt)else(Leftmempty,periodically't0)-- | Produces, whenever the current input signal is 'True'.---- * Depends: Current instant.---- * Inhibits: When input is 'False'.require::(Monoide,WirePure(>~))=>Wiree(>~)Bool()require=mkPureFix(\b->ifbthenRight()elseLeftmempty)-- | Produce as long as the input signal is 'True'. Once it switches to-- 'False', never produce again. Corresponds to 'takeWhile' for lists.---- * Depends: Current instant.---- * Inhibits: As soon as input becomes 'False'.while::(Monoide,WirePure(>~))=>Wiree(>~)Bool()while=mkPure$\b->ifbthen(Right(),while)else(Leftmempty,never)-- | Produces a single event occurence result, when the given 'Bool' is-- true.orGoWith::(Monoide,WirePure(>~))=>Bool->Wiree(>~)ab->(Eithere(),Wiree(>~)ab)orGoWithTrue_=(Right(),never)orGoWithFalsew=(Leftmempty,w)infixl3`orGoWith`