Stability | experimental |
---|---|
Maintainer | conal@conal.net |
Functional events and reactive values. Semantically, an Event
is
stream of future values in time order. A Reactive
value is a
discretly time-varying value.
Many of the operations on events and reactive values are packaged as
instances of the standard type classes Monoid
, Functor
,
Applicative
, and Monad
.
This module focuses on representation and primitives defined in terms of the representation. See also FRP.Reactive.Reactive, which re-exports this module, plus extras that do not exploit the representation. My intention for this separation is to ease experimentation with alternative representations.
Although the basic Reactive
type describes discretely-changing
values, continuously-changing values can be modeled simply as
reactive functions. See FRP.Reactive.Behavior for a convenient type
composition of Reactive
and a constant-optimized representation of
functions of time. The exact packaging of discrete vs continuous will
probably change with more experience.
- data EventG t a
- data ReactiveG t a
- stepper :: a -> EventG t a -> ReactiveG t a
- switcher :: (Ord t, Bounded t) => ReactiveG t a -> EventG t (ReactiveG t a) -> ReactiveG t a
- withTimeGE :: EventG t a -> EventG t (a, Time t)
- withTimeGR :: Time t -> ReactiveG t a -> ReactiveG t (a, Time t)
- futuresE :: (Ord t, Bounded t) => [FutureG t a] -> EventG t a
- futureStreamE :: (Ord t, Bounded t) => Stream (FutureG t a) -> EventG t a
- listEG :: (Ord t, Bounded t) => [(t, a)] -> EventG t a
- atTimesG :: (Ord t, Bounded t) => [t] -> EventG t ()
- atTimeG :: (Ord t, Bounded t) => t -> EventG t ()
- snapshotWith :: (Ord t, Bounded t) => (a -> b -> c) -> ReactiveG t b -> EventG t a -> EventG t c
- accumE :: a -> EventG t (a -> a) -> EventG t a
- accumR :: a -> EventG t (a -> a) -> ReactiveG t a
- once :: (Ord t, Bounded t) => EventG t a -> EventG t a
- withRestE :: EventG t a -> EventG t (a, EventG t a)
- untilE :: (Ord t, Bounded t) => EventG t a -> EventG t b -> EventG t a
- justE :: (Ord t, Bounded t) => EventG t (Maybe a) -> EventG t a
- filterE :: (Ord t, Bounded t) => (a -> Bool) -> EventG t a -> EventG t a
- eventOcc :: Ord t => EventG t a -> FutureG t (a, EventG t a)
- joinMaybes :: MonadPlus m => m (Maybe a) -> m a
- filterMP :: MonadPlus m => (a -> Bool) -> m a -> m a
- result :: (b -> b') -> (a -> b) -> a -> b'
- isMonotoneR :: (Ord t, Bounded t) => ReactiveG t a -> Bool
- batch :: TestBatch
- infE :: EventG NumT NumT
- monoid_E :: TestBatch
Events and reactive values
Events. Semantically: time-ordered list of future values. Instances:
-
Monoid
:mempty
is the event that never occurs, ande
is the event that combines occurrences frommappend
e'e
ande'
. -
Functor
:fmap f e
is the event that occurs whenevere
occurs, and whose occurrence values come from applyingf
to the values frome
. -
Applicative
:pure a
is an event with a single occurrence at time -Infinity.ef <*> ex
is an event whose occurrences are made from the product of the occurrences ofef
andex
. For every occurrencef
at timetf
ofef
and occurrencex
at timetx
ofex
,ef <*> ex
has an occurrencef x
at timetf
. N.B.: I don't expect this instance to be very useful. Ifmax
txef
hasnf
instances andex
hasnx
instances, thenef <*> ex
hasnf*nx
instances. However, there are onlynf+nx
possibilities fortf
, so many of the occurrences are simultaneous. If you think you want to use this instance, consider usingmax
txReactive
instead. -
Monad
:return a
is the same aspure a
(as usual). Ine >>= f
, each occurrence ofe
leads, throughf
, to a new event. Similarly forjoin ee
, which is somehow simpler for me to think about. The occurrences ofe >>= f
(orjoin ee
) correspond to the union of the occurrences (temporal interleaving) of all such events. For example, suppose we're playing Asteroids and tracking collisions. Each collision can break an asteroid into more of them, each of which has to be tracked for more collisions. Another example: A chat room has an enter event, whose occurrences contain new events like speak. An especially useful monad-based function isjoinMaybes
, which filters a Maybe-valued event.
(Ord t, Bounded t) => Monad (EventG t) | |
Functor (EventG t) | |
(Ord t, Bounded t) => MonadPlus (EventG t) | |
(Ord t, Bounded t) => Applicative (EventG t) | |
Unzip (EventG t) | |
(Ord t, Bounded t) => Monoid_f (EventG t) | |
(Ord t, Bounded t) => Alternative (EventG t) | |
Monoid t => Comonad (EventG t) | |
Copointed (EventG t) | |
(Eq t, Bounded t, Show t, Show a) => Show (EventG t a) | |
(Arbitrary t, Ord t, Bounded t, Num t, Arbitrary a) => Arbitrary (EventG t a) | |
(CoArbitrary t, CoArbitrary a) => CoArbitrary (EventG t a) | |
(Ord t, Bounded t) => Monoid (EventG t a) | |
(Ord t, Bounded t, Cozip f) => Zip (:. (EventG t) f) | |
(Ord t, Bounded t) => Monoid_f (:. (EventG t) f) | |
(Bounded t, Eq t, Eq a, EqProp t, EqProp a) => EqProp (EventG t a) | |
(Ord t, Bounded t) => Monoid (:. (EventG t) f a) |
Reactive value: a discretely changing value. Reactive values can be
understood in terms of (a) a simple denotational semantics of reactive
values as functions of time, and (b) the corresponding instances for
functions. The semantics is given by the function at :: ReactiveG t a ->
(t -> a)
. A reactive value may also be thought of (and in this module
is implemented as) a current value and an event (stream of future values).
The semantics of ReactiveG
instances are given by corresponding
instances for the semantic model (functions):
-
Functor
:at (fmap f r) == fmap f (at r)
, i.e.,fmap f r
.at
t == f (rat
t) -
Applicative
:at (pure a) == pure a
, andat (s <*> r) == at s <*> at t
. That is,pure a
, andat
t == a(s <*> r)
.at
t == (sat
t) (rat
t) -
Monad
:at (return a) == return a
, andat (join rr) == join (at . at rr)
. That is,return a
, andat
t == ajoin rr
. As always,at
t == (rrat
t)at
t(r >>= f) == join (fmap f r)
.at (r >>= f) == at r >>= at . f
. -
Monoid
: a typical lifted monoid. Ifo
is a monoid, thenReactive o
is a monoid, withmempty == pure mempty
, andmappend == liftA2 mappend
. That is,mempty
, andat
t == mempty(r
mappend
s)at
t == (rat
t)mappend
(sat
t).
(Ord t, Bounded t) => Monad (ReactiveG t) | |
Functor (ReactiveG t) | |
(Ord t, Bounded t) => Applicative (ReactiveG t) | |
(Ord t, Bounded t) => Zip (ReactiveG t) | |
Unzip (ReactiveG t) | |
Monoid t => Comonad (ReactiveG t) | |
(Ord t, Bounded t) => Pointed (ReactiveG t) | |
Copointed (ReactiveG t) | |
(Eq t, Bounded t, Show t, Show a) => Show (ReactiveG t a) | |
(Arbitrary t, Arbitrary a, Num t, Ord t, Bounded t) => Arbitrary (ReactiveG t a) | |
(CoArbitrary t, CoArbitrary a) => CoArbitrary (ReactiveG t a) | |
(Ord t, Bounded t, Monoid a) => Monoid (ReactiveG t a) | |
(Ord t, Bounded t, Zip f) => Zip (:. (ReactiveG t) f) | |
(Monoid_f f, Ord t, Bounded t) => Monoid_f (:. (ReactiveG t) f) | |
(Ord t, Bounded t, Arbitrary t, Show t, EqProp a) => EqProp (ReactiveG t a) | |
(Ord t, Bounded t) => Model (ReactiveG t a) (t -> a) | |
(Applicative (:. (ReactiveG tr) (Fun tf)), Monoid a) => Monoid (:. (ReactiveG tr) (Fun tf) a) |
Operations on events and reactive values
stepper :: a -> EventG t a -> ReactiveG t aSource
Reactive value from an initial value and a new-value event.
switcher :: (Ord t, Bounded t) => ReactiveG t a -> EventG t (ReactiveG t a) -> ReactiveG t aSource
Switch between reactive values.
withTimeGE :: EventG t a -> EventG t (a, Time t)Source
Access occurrence times in an event. See also withTimeGR
.
withTimeGR :: Time t -> ReactiveG t a -> ReactiveG t (a, Time t)Source
Access occurrence times in a reactive value. See also withTimeGE
.
futuresE :: (Ord t, Bounded t) => [FutureG t a] -> EventG t aSource
Convert a temporally monotonic list of futures to an event
futureStreamE :: (Ord t, Bounded t) => Stream (FutureG t a) -> EventG t aSource
Convert a temporally monotonic stream of futures to an event. Like
futuresE
but it can be lazier, because there's not empty case.
listEG :: (Ord t, Bounded t) => [(t, a)] -> EventG t aSource
Convert a temporally monotonic list of futures to an event. See also
the specialization listE
snapshotWith :: (Ord t, Bounded t) => (a -> b -> c) -> ReactiveG t b -> EventG t a -> EventG t cSource
Snapshot a reactive value whenever an event occurs and apply a combining function to the event and reactive's values.
accumE :: a -> EventG t (a -> a) -> EventG t aSource
Accumulating event, starting from an initial value and a
update-function event. See also accumR
.
accumR :: a -> EventG t (a -> a) -> ReactiveG t aSource
Reactive value from an initial value and an updater event. See also
accumE
.
withRestE :: EventG t a -> EventG t (a, EventG t a)Source
Access the remainder with each event occurrence.
untilE :: (Ord t, Bounded t) => EventG t a -> EventG t b -> EventG t aSource
Truncate first event at first occurrence of second event.
justE :: (Ord t, Bounded t) => EventG t (Maybe a) -> EventG t aSource
Experimental specialization of joinMaybes
.
filterE :: (Ord t, Bounded t) => (a -> Bool) -> EventG t a -> EventG t aSource
Experimental specialization of filterMP
.
eventOcc :: Ord t => EventG t a -> FutureG t (a, EventG t a)Source
Extract a future representing the first occurrence of the event together with the event of all occurrences after that one.
To be moved elsewhere
joinMaybes :: MonadPlus m => m (Maybe a) -> m aSource
Pass through Just
occurrences.
result :: (b -> b') -> (a -> b) -> a -> b'Source
Apply a given function inside the results of other functions. Equivalent to '(.)', but has a nicer reading when composed