As J. Abrahamson pointed out in the comments, a Behavior
varies continuously in time, so the discrete events that mark changes to a Behavior
aren't well defined. Here are some alternatives.
Change behavior by event
If you are using the reactive package and are looking at changing Behavior
s based on Event
s, then switcher
has the correct type:
switcher :: Behavior a -> Event (Behavior a) -> Behavior a
Accumulate events with reset
As you mention in the comments, if you want to reset an accumulator on an event to x
, simply put a const x
event in the stream. This example uses the reactive package.
accumBReset :: a -> Event a -> Event (a -> a) -> Behavior a
accumBReset initial resets changes =
accumB initial allChanges
where
allChanges = (fmap const resets) `mappend` changes
Reactive
In Push-pull Functional Reactive Programming, Conal Elliott describes the Reactive
type, which is analogous to a Behavior
that only changes at discrete moments in time.
data Reactive a = a `Stepper` Event a
newtype Event a = Ev (Future (Reactive a))
Reactive
can be converted into a stream of events marking its changes by deconstructing it and taking the right side of the constructor which is the event that next changes its value
changes :: Reactive a -> Event a
changes (_ `Stepper` nextChange) = nextChange
Alternatively, we could get all the values of the Reactive, including what it is now and all of its future changes
values :: Reactive a -> Event a
values = Ev . pure
Reactive
values are in FRP.Reactive.Reactive
in the reactive package.
Get changes from a Behavior at a lower level
In some FRP libraries, you can do more at a lower level. In reactive-banana you can observe changes
to a Behavior
when making your own Framework
. Here's the type for Reactive.Banana.Framework
's changes
changes :: Frameworks t => Behavior t a -> Moment t (Event t (Future a))
The documentation warns that this isn't really meaningful:
Output, observe when a Behavior
changes.
Strictly speaking, a Behavior
denotes a value that varies continuously
in time, so there is no well-defined event which indicates when the
behavior changes.
Still, for reasons of efficiency, the library provides a way to
observe changes when the behavior is a step function, for instance as
created by stepper
. There are no formal guarantees, but the idea is
that
changes (stepper x e) = return (calm e)
Note: The values of the event
will not become available until event processing is complete. It can
be used only in the context of reactimate'
.