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:
+ +-
+
- Preservation of identity:
lift!(|x| x, &a) == a
,
+ - Function composition:
lift!(|x| g(f(x)), &a) == lift!(g, &lift!(f, &a))
.
+
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); +} ++