Elerea (Eventless Reactivity) is a simplistic FRP implementation that parts with the concept of events, and introduces various constructs that can be used to define completely dynamic higher-order dataflow networks. The user sees the functionality through a hybrid monadic-applicative interface, where stateful signals can only be created through a specialised monad, while most combinators are purely applicative. The combinators build up a network of interconnected mutable references in the background. The network is executed iteratively, where each superstep consists of three 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,cosine) <- mdo s <- integral 0 c c <- integral 1 (-s) return (s,c)
integral is not a primitive, it can be defined by the user
as a transfer function. A possible implementation that can be used on
Fractional signal looks like this:
integral x0 s = transfer x0 (\dt x x0 -> x0+x*realToFrac dt) s
Head to FRP.Elerea.Legacy.Internal for the implementation details.
To get a general idea how to use the library, check out the sources in
The FRP.Elerea branch provides a similar interface with a rather different underlying structure, which is likely to be more efficient.
- type DTime = Double
- type Sink a = a -> IO ()
- data Signal a
- data SignalMonad a
- createSignal :: SignalMonad a -> IO a
- superstep :: Signal a -> DTime -> IO a
- external :: a -> IO (Signal a, Sink a)
- stateful :: a -> (DTime -> a -> a) -> SignalMonad (Signal a)
- transfer :: a -> (DTime -> t -> a -> a) -> Signal t -> SignalMonad (Signal a)
- delay :: a -> Signal a -> SignalMonad (Signal a)
- sampler :: Signal (Signal a) -> Signal a
- generator :: Signal Bool -> Signal (SignalMonad a) -> Signal (Maybe a)
- storeJust :: a -> Signal (Maybe a) -> SignalMonad (Signal a)
- toMaybe :: Bool -> a -> Maybe a
- edge :: Signal Bool -> SignalMonad (Signal Bool)
- keepAlive :: Signal a -> Signal t -> Signal a
- (.@.) :: Signal a -> Signal t -> Signal a
- (==@) :: 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
- signalDebug :: Show a => a -> SignalMonad ()
A signal is conceptually a time-varying value.
|Bounded t => Bounded (Signal t)|
|Enum t => Enum (Signal t)|
|Eq (Signal a)|
The equality test checks whether two signals are physically the same.
|Floating t => Floating (Signal t)|
|Fractional t => Fractional (Signal t)|
|Integral t => Integral (Signal t)|
|Num t => Num (Signal t)|
|Ord t => Ord (Signal t)|
|Real t => Real (Signal t)|
|Show (Signal a)|
A restricted monad to create stateful signals in.
|:: Signal a|
the top-level signal
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.
A pure stateful signal. The initial state is the first output.
initial internal state
|-> (DTime -> t -> a -> a)|
state updater function
|-> Signal t|
|-> SignalMonad (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
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.
A continuous sampler that flattens a higher-order signal by outputting its current snapshots.
|:: Signal Bool|
control (trigger) signal
|-> Signal (SignalMonad a)|
a stream of monads to potentially run
|-> Signal (Maybe a)|
A reactive signal that takes the value to output from a monad
carried by its input when a boolean control signal is true, otherwise
Nothing. It is possible to create new signals in the
monad and also to print debug messages.
A helper function to wrap any value in a
Maybe depending on a
edge transfer function takes a bool signal and emits another
bool signal that turns true only at the moment when there is a rising
edge on the input.
|:: 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.