Elerea (Eventless Reactivity) is a simplistic FRP implementation that parts with the concept of events, and uses a continuous latching construct instead. The user sees the functionality through an applicative interface, which is used to build up a network of interconnected mutable references. The network is executed iteratively, where each superstep consists of two phases: sampling-aging and finalisation. As an example, the following code is a possible way to define an approximation of our beloved trig functions:
sine = integral 0 cosine cosine = integral 1 (-sine)
Note that integral
is not a primitive, it can be defined by the user
as a transfer function. A possible implementation that can be used on
any Fractional
signal looks like this:
integral x0 s = transfer x0 (\dt x x0 -> x0+x*realToFrac dt) s
Head to FRP.Elerea.Internal for the implementation details. To get
a general idea how to use the library, check out the sources in the
elerea-examples
package.
- type DTime = Double
- type Sink a = a -> IO ()
- data Signal a
- data StartToken
- superstep :: Signal a -> DTime -> IO a
- external :: a -> IO (Signal a, Sink a)
- keepAlive :: Signal a -> Signal t -> Signal a
- (.@.) :: Signal a -> Signal t -> Signal a
- stateful :: a -> (DTime -> a -> a) -> Signal a
- transfer :: a -> (DTime -> t -> a -> a) -> Signal t -> Signal a
- latcher :: Signal a -> Signal Bool -> Signal (Signal a) -> Signal a
- delay :: a -> Signal a -> Signal a
- startTokens :: Signal StartToken
- (==>) :: StartToken -> a -> a
- edge :: Signal Bool -> Signal Bool
- (==@) :: Eq a => Signal a -> Signal a -> Signal Bool
- (/=@) :: Eq a => Signal a -> Signal a -> Signal Bool
- (<@) :: Ord a => Signal a -> Signal a -> Signal Bool
- (<=@) :: Ord a => Signal a -> Signal a -> Signal Bool
- (>=@) :: Ord a => Signal a -> Signal a -> Signal Bool
- (>@) :: Ord a => Signal a -> Signal a -> Signal Bool
- (&&@) :: Signal Bool -> Signal Bool -> Signal Bool
- (||@) :: Signal Bool -> Signal Bool -> Signal Bool
Documentation
A signal is represented as a transactional structural node.
Functor Signal | |
Applicative Signal | The |
Eq (Signal a) | The equality test checks whether two signals are physically the same. |
Floating t => Floating (Signal t) | |
Fractional t => Fractional (Signal t) | |
Num t => Num (Signal t) | |
Show (Signal a) | The |
data StartToken Source
An empty type to use as a token for injecting data dependencies.
:: Signal a | the top-level signal |
-> DTime | the amount of time to advance |
-> IO a | the current value of the signal |
Advancing the whole network that the given signal depends on by the amount of time given in the second argument.
A signal that can be directly fed through the sink function returned. This can be used to attach the network to the outer world.
:: Signal a | the actual output |
-> Signal t | a signal guaranteed to age when this one is sampled |
-> Signal a |
Dependency injection to allow aging signals whose output is not
necessarily needed to produce the current sample of the first
argument. It's equivalent to (flip . liftA2 . flip) const
, as it
evaluates its second argument first.
A pure stateful signal. The initial state is the first output.
:: a | initial internal state |
-> (DTime -> t -> a -> a) | state updater function |
-> Signal t | input signal |
-> Signal a |
A stateful transfer function. The current input affects the
current output, i.e. the initial state given in the first argument is
considered to appear before the first output, and can only be directly
observed by the sampleDelayed
function.
:: Signal a |
|
-> Signal Bool |
|
-> Signal (Signal a) |
|
-> Signal a |
Reactive signal that starts out as s
and can change its
behaviour to the one supplied in ss
whenever e
is true. The
change can be observed immediately, unless the signal is sampled by
sampleDelayed
, which puts a delay on the latch control (but not on
the latched signal!).
The delay
transfer function emits the value of a signal from the
previous superstep, starting with the filler value given in the first
argument. It has to be a primitive, otherwise it could not be used to
prevent automatic delays.
startTokens :: Signal StartTokenSource
A stream of tokens freshly generated in each superstep. These are
dummy values that must not be evaluated (they are in fact
undefined
), but distributed among signals that need to be
constructed at the given moment in the absence of other dependencies
on current values, so as to prevent let-floating from moving otherwise
independent signals to an outer scope. Dependency on these tokens can
be established with the ==>
operator.
(==>) :: StartToken -> a -> aSource
An operator that ignores its first argument and returns the
second, but hides the fact that the first argument is not needed. It
is equivalent to flip const
, but it cannot be inlined.