{-----------------------------------------------------------------------------
Reactive Banana
------------------------------------------------------------------------------}{-# LANGUAGE Rank2Types, MultiParamTypeClasses,
TypeSynonymInstances, FlexibleInstances #-}moduleReactive.Banana.Experimental.Calm(-- * Synopsis-- | Experimental module: API change very likely.---- 'Event' type that disallows simultaneous event occurrences.---- The combinators behave essentially as their counterparts-- in "Reactive.Banana.Combinators".-- * Main typesEvent,Behavior,collect,fromCalm,interpret,-- * Core CombinatorsmoduleControl.Applicative,never,unionWith,filterE,accumE,apply,stepper,-- $classes-- * Derived Combinators-- ** FilteringfilterJust,-- ** Accumulation-- $Accumulation.accumB,mapAccum,-- ** Apply classReactive.Banana.Combinators.Apply(..),)whereimportControl.ApplicativeimportControl.MonadimportData.Maybe(listToMaybe)importqualifiedReactive.Banana.CombinatorsasPrimimportqualifiedReactive.Banana.Combinators{-----------------------------------------------------------------------------
Main types
------------------------------------------------------------------------------}newtypeEventta=E{unE::Prim.Eventta}typeBehaviort=Reactive.Banana.Combinators.Behaviort-- | Convert event with possible simultaneous occurrences-- into an 'Event' with a single occurrence.collect::Reactive.Banana.Combinators.Eventta->Eventt[a]collect=E.Prim.collect-- | Convert event with single occurrences into-- event with possible simultaneous occurrencesfromCalm::Eventta->Reactive.Banana.Combinators.EventtafromCalm=unEsingletonx=[x]-- | Interpretation function.-- Useful for testing.interpret::(forallt.Eventta->Eventtb)->[a]->IO[Maybeb]interpretfxs=maplistToMaybe<$>Prim.interpret(unE.f.E)(mapsingletonxs){-----------------------------------------------------------------------------
Core Combinators
------------------------------------------------------------------------------}-- | Event that never occurs.-- Think of it as @never = []@.never::Eventtanever=E$Prim.never-- | Merge two event streams of the same type.-- Combine simultaneous values if necessary.unionWith::(a->a->a)->Eventta->Eventta->EventtaunionWithfe1e2=E$Prim.unionWithf(unEe1)(unEe2)-- | Allow all events that fulfill the predicate, discard the rest.filterE::(a->Bool)->Eventta->EventtafilterEp=E.Prim.filterEp.unE-- | Construct a time-varying function from an initial value and -- a stream of new values.stepper::a->Eventta->Behaviortastepperxe=Prim.stepperx(unEe)-- | The 'accumE' function accumulates a stream of events.accumE::a->Eventt(a->a)->EventtaaccumEacc=E.Prim.accumEacc.unE-- | Apply a time-varying function to a stream of events.apply::Behaviort(a->b)->Eventta->Eventtbapplyb=E.Prim.applyb.unEinstanceFunctor(Eventt)wherefmapf=E.fmapf.unE{-----------------------------------------------------------------------------
Derived Combinators
------------------------------------------------------------------------------}-- | Keep only the 'Just' values.-- Variant of 'filterE'.filterJust::Eventt(Maybea)->EventtafilterJust=E.Prim.filterJust.unE-- | The 'accumB' function is similar to a /strict/ left fold, 'foldl''.-- It starts with an initial value and combines it with incoming events.accumB::a->Eventt(a->a)->BehaviortaaccumBacc=Prim.accumBacc.unE-- $Accumulation.-- Note: all accumulation functions are strict in the accumulated value!-- acc -> (x,acc) is the order used by 'unfoldr' and 'State'.-- | Efficient combination of 'accumE' and 'accumB'.mapAccum::acc->Eventt(acc->(x,acc))->(Eventtx,Behaviortacc)mapAccumaccef=let(e,b)=Prim.mapAccumacc(unEef)in(Ee,b)instanceReactive.Banana.Combinators.Apply(Behaviort)(Eventt)where(<@>)=apply