Note: I have retired the old version of Reactive on darcs.haskell.org.
Please use the new Reactive.

Reactive is a simple foundation for programming reactive systems functionally. Like Fran/FRP, it has a notions of (reactive) behaviors and events. Like DataDriven, Reactive has an efficient, data-driven implementation. The main difference between Reactive and DataDriven are

Reactive provides and builds on "functional futures", which in turn build on Concurrent Haskell threads, while DataDriven builds on continuation-based computations; and

The algebras of events and reactive values (called events and sources in DataDriven) are purely functional. I couldn't figure out how to accomplish that in DataDriven.

Reactive manages (I hope) to get the efficiency of data-driven computation with a (sort-of) demand-driven architecture. For that reason, Reactive is garbage-collector-friendly, while DataDriven depends on weak references (because GC favors demand-driven computation.)

Reactive elegantly and efficiently caches values.

Reactive uses the term "reactive values" (

Reactive

), where DataDriven uses "sources" (

Source

).

The inspiration for Reactive was Mike Sperber's Lula implementation of FRP. Mike used blocking threads, which I had never considered for FRP before a conversation with him at ICFP 2007. While playing with the idea, I realized that I could give a very elegant and efficient solution to caching, which DataDriven doesn't do. (For an application

f <*> a

of a varying function to a varying argument, caching remembers the latest function to apply to a new argument and the latest argument to which to apply a new function.)
As with DataDriven, Reactive provides instances for

Monoid

,

Functor

,

Applicative

, and

Monad

.

Besides this wiki page, here are more ways to find out about Reactive:

A future is a value that will become knowable only later. Primitive futures can be things like "the value of the next key you press", or "the value of LambdaPix stock at noon next Monday". The term "promise" might be more fitting.

Composition is via standard type classes:

Functor

,

Applicative

,

Monad

, and

Monoid

.

Monoid

:

mempty

is a future that never becomes knowable.

a `mappend` b

is whichever of

a

and

b

is knowable first.

Functor

: apply a function to a future. The result is knowable when the given future is knowable.

Applicative

:

pure

gives value knowable since the beginning of time.

(<*>)

applies a future function to a future argument. Result available when both are available, i.e., it becomes knowable when the later of the two futures becomes knowable.

Monad:

return

is the same as

pure

(as always).

(>>=)

cascades futures.

join

resolves a future future value into a future value.

The current implementation is nondeterministic in

mappend

for futures that become knowable at the same time or nearly the same time. I want to make a deterministic implementation.

(sometimes called "parallel or"). Once one thread completes, the other threads are then useless, and some might consume resources forever. My current implementation kill the losing threads. Baker & Hewitt suggest instead using garbage collection. I'm stumped about how to GC non-winning threads in a race between futures ("parallel or"). The winner-kills-loser approach seems to work fine, though is potentially dangerous w.r.t locked resources. Still, the elegance of a GC-based solution appeals to me.

This module defines events and reactive values. An event is stream of future values in order of availability. A reactive value is a discretly time-varying value. These two types are closely linked: a reactive value is defined by an initial value and an event that yields future values; while an event is simply a future reactive value.

representation can be thought of a reactive weak head normal form, to which arbitrary reactive expressions may be rewritten. The rewrite rules and their justification in terms of simple denotational semantics will be described in an upcoming paper.

Many of the operations on events and reactive values are packaged as instances of standard classes, as described below. See the module documentation for the other operations.

is an event with a single occurrence, available from the beginning of time.

ef <*> ex

is an event whose occurrences are made from the product of the occurrences of

ef

and

ex

. For every occurrence

f

at time

tf

of

ef

and occurrence

x

at time

tx

of

ex

,

ef <*> ex

has an occurrence

f x

at time

max tf tx

.

Monad

:

return a

is the same as

pure a

(as always). In

e >>= f

, each occurrence of

e

leads, through

f

, to a new event. Similarly for

join ee

, which is somehow simpler for me to think about. The occurrences of

e >>= f

(or

join ee

) correspond to the union of the occurrences 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".