Struct carboxyl::Signal [] [src]

pub struct Signal<A> {
    // some fields omitted
}

A continuous signal that changes over time.

Signals can be thought of as values that change over time. They have both a continuous and a discrete component. This means that their current value is defined by a function that can be called at any time. That function is only evaluated on-demand, when the signal's current value is sampled. (This is also called pull semantics in the literature on FRP.)

In addition, the current function used to sample a signal may change discretely in reaction to some event. For instance, it is possible to create a signal from an event stream, by holding the last event occurence as the current value of the stream.

Algebraic laws

Signals come with some primitive methods to compose them with each other and with streams. Some of these primitives give the signals an algebraic structure.

Functor

Signals form a functor under unary lifting. Thus, the following laws hold:

Applicative functor

By extension, using the notion of a signal of a function, signals also become an applicative using Signal::new as pure and |sf, sa| lift!(|f, a| f(a), &sf, &sa) as <*>.

TODO: Expand on this and replace the Haskell reference.

Methods

impl<A: Clone + 'static> Signal<A>

fn new(a: A) -> Signal<A>

Create a constant signal.

fn sample(&self) -> A

Sample the current value of the signal.

impl<A: Clone + Send + Sync + 'static> Signal<A>

fn cyclic<F>(def: F) -> Signal<A> where F: FnOnce(&Signal<A>) -> Signal<A>

Create a signal with a cyclic definition.

The closure gets an undefined forward-declaration of a signal. It is supposed to return a self-referential definition of the same signal.

Sampling the forward-declared signal, before it is properly defined, will cause a run-time panic.

This pattern is useful to implement accumulators, counters and other loops that depend on the sampling behaviour of a signal before a transaction.

fn snapshot<B, C, F>(&self, stream: &Stream<B>, f: F) -> Stream<C> where B: Clone + Send + Sync + 'static, C: Clone + Send + Sync + 'static, F: Fn(A, B) -> C + Send + Sync + 'static

Combine the signal with a stream in a snapshot.

snapshot creates a new stream given a signal and a stream. Whenever the input stream fires an event, the output stream fires an event created from the signal's current value and that event using the supplied function.

let sink1: Sink<i32> = Sink::new();
let sink2: Sink<f64> = Sink::new();
let mut events = sink1.stream().hold(1)
    .snapshot(&sink2.stream(), |a, b| (a, b))
    .events();

// Updating its signal does not cause the snapshot to fire
sink1.send(4);

// However sending an event down the stream does
sink2.send(3.0);
assert_eq!(events.next(), Some((4, 3.0)));

impl<A: Clone + Send + Sync + 'static> Signal<Signal<A>>

fn switch(&self) -> Signal<A>

Switch between signals.

This transforms a Signal<Signal<A>> into a Signal<A>. The nested signal can be thought of as a representation of a switch between different input signals, that allows one to change the structure of the dependency graph at run-time. switch provides a way to access the inner value of the currently active signal.

The following example demonstrates how to use this to switch between two input signals based on a Button event stream:

// Button type
#[derive(Clone, Show)]
enum Button { A, B };

// The input sinks
let sink_a = Sink::<i32>::new();
let sink_b = Sink::<i32>::new();

// The button sink
let sink_button = Sink::<Button>::new();

// Create the output
let output = {

    // Hold input sinks in a signal with some initials
    let channel_a = sink_a.stream().hold(1);
    let channel_b = sink_b.stream().hold(2);

    // A trivial default channel used before any button event
    let default_channel = Sink::new().stream().hold(0);

    // Map button to the channel signals, hold with the default channel as
    // initial value and switch between the signals
    sink_button
        .stream()
        .map(move |b| match b {
            Button::A => channel_a.clone(),
            Button::B => channel_b.clone(),
        })
        .hold(default_channel)
        .switch()
};

// In the beginning, output will come from the default channel
assert_eq!(output.sample(), 0);

// Let's switch to channel A
sink_button.send(Button::A);
assert_eq!(output.sample(), 1);

// And to channel B
sink_button.send(Button::B);
assert_eq!(output.sample(), 2);

// The channels can change, too, of course
for k in 4..13 {
    sink_b.send(k);
    assert_eq!(output.sample(), k);
}
sink_button.send(Button::A);
for k in 21..77 {
    sink_a.send(k);
    assert_eq!(output.sample(), k);
}

Trait Implementations

impl<A> Clone for Signal<A>

fn clone(&self) -> Signal<A>

fn clone_from(&mut self, source: &Self)

impl<A: Debug + Clone + 'static> Debug for Signal<A>

fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error>