README.md

# Reactive Elixir

Reactive Elixir is a small library to do reactive programming in Elixir. It's
main purpose is to expiriment in an academic setting. My personal goal with this
project is to run it on raspberry pi's and simulate IoT devices.

Concretly it needs to have the following features.

 * Simulate source signals (e.g., mouse location, temperature sensor value,..)
 * Create a DAG of source nodes, internal nodes, and sinks.

The library does not offer any kind of glitch freedom.

## Source vs Derived 

### Source Signal
A source signal is a signal that is reified into the runtime. For example,
Flapjax offers you the mouse position as a source signal. Because I want to
_simulate_ devices with several signals, I have decided to allow setting up a
few source signals.

We create a temperature signal using `Reactive.Signal.Source.new/4`.

```
{:ok, t} = Source.new(fn(_old_value) -> Enum.random(10..100) end, -1, 5000, :temperature)
```

The parameters are the following.

 1. The function that generates a new value with the old one as the parameter.
 2. The initial value.
 3. The time between two signal generations.
 4. The human readable name of the signal.
 
 ### Derived Signal
 
 A derived signal, as the name hints, is a signal that is derived from the value
 of another signal. These can be either source or derived signals.
 
 Assume we have the signal `t` in scope from the previous example. We can create
 a new signal based on that which generates "hot" or "cold".

```
t
|> Reactive.liftapp(&hot_cold/1)
```

The `&hot_cold/1` function takes in an integer representing the temperature and
returns "hot" or "cold" based on the value.  We can *lift* this function into a
signal world by calling `Reactive.lift/1` on it. This returns a function that
takes a Signal Integer and turns it into a String Integer.

To hook this lifted function up to the signal we need to `apply` it to the
signal. Mind you that the function that is lifted is merely a function. We need
to apply it in order for it to execute. `liftapp/2` is a shorthand for
`apply(lift(f), signal)`.

## Register 

If an actor consumes many signals, and produces new signals, we might want to
publish them for other actors to consume them. This is where the ETS table comes
in. Each signal can be registered globally and read globally through the
`Registry`.

Any signal can be registered using `Reactivity.register/2`. Consider the example
below.

```
  def hot_cold(t) do
    if t > 30 do
      "hot"
    else
      "cold"
    end
  end
  
  def test do
    # Create a new signal :hotcold based on the source :temperature.
    source(:temperature)
    |> liftapp(&hot_cold/1)
    |> register(:hotcold)

  end
```

We know that there is a global signal `:temperature` and we can grab that by
calling `source(:temperature)`. this will return us a handle to that signal so
we can `liftapp` over that signal. If we create a new signal (e.g., from Kelvin
to Celcius) we can register that one, too. In the above example we register a
new signal, producing the values `"hot"` or `"cold"`, under the name `:hotcold`.

## Installation

```elixir
def deps do
  [{:reactivity, "~> 0.1.0"}]
end
```