Safe Haskell | Safe-Infered |
---|

- module Control.Applicative
- class (Functor (Event f), Functor (Behavior f), Applicative (Behavior f)) => FRP f where
- never :: Event f a
- union :: Event f a -> Event f a -> Event f a
- apply :: Behavior f (a -> b) -> Event f a -> Event f b
- filterE :: (a -> Bool) -> Event f a -> Event f a
- filterApply :: Behavior f (a -> Bool) -> Event f a -> Event f a
- stepper :: a -> Event f a -> Behavior f a
- accumB :: a -> Event f (a -> a) -> Behavior f a
- accumE :: a -> Event f (a -> a) -> Event f a

- data family Event f :: * -> *
- data family Behavior f :: * -> *
- whenE :: FRP f => Behavior f Bool -> Event f a -> Event f a
- filterJust :: FRP f => Event f (Maybe a) -> Event f a
- mapAccum :: FRP f => acc -> Event f (acc -> (x, acc)) -> (Event f x, Behavior f acc)
- class (Functor f, Functor g) => Apply f g where
- data Model
- type Time = Double
- interpretTime :: (Event Model a -> Event Model b) -> [(Time, a)] -> [(Time, b)]
- interpret :: (Event Model a -> Event Model b) -> [a] -> [[b]]

# Synopsis

Combinators for building event networks and their semantics.

# Core Combinators

module Control.Applicative

class (Functor (Event f), Functor (Behavior f), Applicative (Behavior f)) => FRP f whereSource

The `FRP`

class defines the primitive API for functional reactive programming.
Each instance `f`

defines two type constructors `Event f`

and `Behavior f`

and corresponding combinators.

`Event f a`

represents a stream of events as they occur in time.
Semantically, you can think of `Event f a`

as an infinite list of values
that are tagged with their corresponding time of occurence,

type Event f a = [(Time,a)]

`Behavior f a`

represents a value that varies in time. Think of it as

type Behavior f a = Time -> a

While these type synonyms are the way you should think about
`Behavior`

and `Event`

, they are a bit vague for formal manipulation.
To remedy this, the library provides a very simple model implementation,
called `Model`

.
This model is *authoritative*: every instance of the `FRP`

class *must*
give the same results as the model when observed with the `interpret`

function.
Note that this must also hold for recursive and partial definitions
(at least in spirit, I'm not going to split hairs over `_|_`

vs `\_ -> _|_`

).

Concerning time and space complexity, the model is not authoritative, however. Implementations are free to be much more efficient.

Minimal complete definition of the `FRP`

class: One of `filter`

or `filterApply`

and one of `accumB`

or `stepper`

.

Event that never occurs.
Think of it as `never = []`

.

union :: Event f a -> Event f a -> Event f aSource

Merge two event streams of the same type. In case of simultaneous occurrences, the left argument comes first. Think of it as

union ((timex,x):xs) ((timey,y):ys) | timex <= timey = (timex,x) : union xs ((timey,y):ys) | timex > timey = (timey,y) : union ((timex,x):xs) ys

apply :: Behavior f (a -> b) -> Event f a -> Event f bSource

Apply a time-varying function to a stream of events. Think of it as

apply bf ex = [(time, bf time x) | (time, x) <- ex]

filterE :: (a -> Bool) -> Event f a -> Event f aSource

Allow all events that fulfill the predicate, discard the rest. Think of it as

filterE p es = [(time,a) | (time,a) <- es, p a]

filterApply :: Behavior f (a -> Bool) -> Event f a -> Event f aSource

Allow all events that fulfill the time-varying predicate, discard the rest.
It's a slight generalization of `filterE`

.

stepper :: a -> Event f a -> Behavior f aSource

Construct a time-varying function from an initial value and a stream of new values. Think of it as

stepper x0 ex = \time -> last (x0 : [x | (timex,x) <- ex, timex < time])

Note that the smaller-than-sign in the comparision `timex < time`

means
that the value of the behavior changes "slightly after"
the event occurrences. This allows for recursive definitions.

Also note that in the case of simultaneous occurrences, only the last one is kept.

accumB :: a -> Event f (a -> a) -> Behavior f aSource

The `accumB`

function is similar to a *strict* left fold, `foldl'`

.
It starts with an initial value and combines it with incoming events.
For example, think

accumB "x" [(time1,(++"y")),(time2,(++"z"))] = stepper "x" [(time1,"xy"),(time2,"xyz")]

Note that the value of the behavior changes "slightly after" the events occur. This allows for recursive definitions.

*Further combinators that Haddock can't document properly.*

instance FRP f => Monoid (Event f a)

The combinators `never`

and `union`

turn `Event`

into a monoid.

instance FPR f => Applicative (Behavior f)

`Behavior`

is an applicative functor. In particular, we have the following functions.

pure :: FRP f => a -> Behavior f a

The constant time-varying value. Think of it as `pure x = \time -> x`

.

(<*>) :: FRP f => Behavior f (a -> b) -> Behavior f a -> Behavior f b

Combine behaviors in applicative style.
Think of it as `bf <*> bx = \time -> bf time $ bx time`

.

# Derived Combinators

class (Functor f, Functor g) => Apply f g whereSource

Class for overloading the `apply`

function.

# Model implementation

The type index `Model`

represents the model implementation.
You are encouraged to look at the source code!
(If there is no link to the source code at every type signature,
then you have to run `cabal`

with `--hyperlink-source`

flag.)