React.S

# Module React.S

    module S: sig .. end

Signal combinators.

Consult their semantics.

# Primitive and basics

    type 'a t = 'a React.signal

The type for signals of type `'a`.

    val const : 'a -> 'a React.signal

`const v` is always `v`, [`const v`]t `= v`.

    val create : ?eq:('a -> 'a -> bool) ->
           'a -> 'a React.signal * (?step:React.step -> 'a -> unit)

`create i` is a primitive signal `s` set to `i` and a `set` function. The function `set` is such that:

- `set v` sets the signal's value to `v` at the time it is called and triggers an update step.
- `set ~step v` sets the signal's value to `v` at the time it is called and updates it dependencies when `step` is executed
- `set ~step v` raises `Invalid_argument` if it was previously called with a step and this step has not executed yet or if the given `step` was already executed.

Warning. `set` must not be executed inside an update step.

    val value : 'a React.signal -> 'a

`value s` is `s`'s current value.

Warning. If executed in an update step may return a non up-to-date value or raise `Failure` if the signal is not yet initialized.

    val retain : 'a React.signal -> (unit -> unit) -> [ `R of unit -> unit ]

`retain s c` keeps a reference to the closure `c` in `s` and returns the previously retained value. `c` will never be invoked.

Raises. `Invalid_argument` on constant signals.

    val stop : ?strong:bool -> 'a React.signal -> unit

`stop s`, stops updating `s`. It conceptually becomes `React.S.const` with the signal's last value and cannot be restarted. Allows to disable effectful signals.

The `strong` argument should only be used on platforms where weak arrays have a strong semantics (i.e. JavaScript). See details.

Note. If executed in an update step the signal may still update in the step.

    val equal : ?eq:('a -> 'a -> bool) -> 'a React.signal -> 'a React.signal -> bool

`equal s s'` is `true` iff `s` and `s'` are equal. If both signals are `React.S.const`ant `eq` is used between their value (defauts to structural equality). If both signals are not `React.S.const`ant, physical equality is used.

    val trace : ?iff:bool t -> ('a -> unit) -> 'a React.signal -> 'a React.signal

`trace iff tr s` is `s` except `tr` is invoked with `s`'s current value and on `s` changes when `iff` is `true` (defaults to `S.const true`). For all t where [`s`]t `= v` and (t = 0 or ([`s`]t-dt`= v'` and `eq v v' = false`)) and [`iff`]t = `true`, `tr` is invoked with `v`.

# From events

    val hold : ?eq:('a -> 'a -> bool) -> 'a -> 'a React.event -> 'a React.signal

`hold i e` has the value of `e`'s last occurrence or `i` if there wasn't any.

- [`hold i e`]t `= i` if [`e`]<=t `= None`
- [`hold i e`]t `= v` if [`e`]<=t `= Some v`

# Transforming and filtering

    val app : ?eq:('b -> 'b -> bool) ->
           ('a -> 'b) React.signal -> 'a React.signal -> 'b React.signal

`app sf s` holds the value of `sf` applied to the value of `s`, [`app sf s`]t `=` [`sf`]t [`s`]t.

    val map : ?eq:('b -> 'b -> bool) -> ('a -> 'b) -> 'a React.signal -> 'b React.signal

`map f s` is `s` transformed by `f`, [`map f s`]t = `f` [`s`]t.

    val filter : ?eq:('a -> 'a -> bool) ->
           ('a -> bool) -> 'a -> 'a React.signal -> 'a React.signal

`filter f i s` is `s`'s values that satisfy `p`. If a value does not satisfy `p` it holds the last value that was satisfied or `i` if there is none.

- [`filter p s`]t `=` [`s`]t if `p` [`s`]t`= true`.
- [`filter p s`]t `=` [`s`]t' if `p` [`s`]t`= false` and t' is the greatest t' < t with `p` [`s`]t'`= true`.
- [`filter p e`]t `= i` otherwise.

    val fmap : ?eq:('b -> 'b -> bool) ->
           ('a -> 'b option) -> 'b -> 'a React.signal -> 'b React.signal

`fmap fm i s` is `s` filtered and mapped by `fm`.

- [`fmap fm i s`]t `=` v if `fm` [`s`]t`= Some v`.
- [`fmap fm i s`]t `=` [`fmap fm i s`]t' if `fm` [`s`]t `= None` and t' is the greatest t' < t with `fm` [`s`]t' `<> None`.
- [`fmap fm i s`]t `= i` otherwise.

    val diff : ('a -> 'a -> 'b) -> 'a React.signal -> 'b React.event

`diff f s` is an event with occurrences whenever `s` changes from `v'` to `v` and `eq v v'` is `false` (`eq` is the signal's equality function). The value of the occurrence is `f v v'`.

- [`diff f s`]t `= Some d` if [`s`]t `= v` and [`s`]t-dt `= v'` and `eq v v' = false` and `f v v' = d`.
- [`diff f s`]t `= None` otherwise.

    val changes : 'a React.signal -> 'a React.event

`changes s` is `diff (fun v _ -> v) s`.

    val sample : ('b -> 'a -> 'c) -> 'b React.event -> 'a React.signal -> 'c React.event

`sample f e s` samples `s` at `e`'s occurrences.

- [`sample f e s`]t `= Some (f ev sv)` if [`e`]t `= Some ev` and [`s`]t `= sv`.
- [`sample e s`]t `= None` otherwise.

    val on : ?eq:('a -> 'a -> bool) ->
           bool React.signal -> 'a -> 'a React.signal -> 'a React.signal

`on c i s` is the signal `s` whenever `c` is `true`. When `c` is `false` it holds the last value `s` had when `c` was the last time `true` or `i` if it never was.

- [`on c i s`]t `=` [`s`]t if [`c`]t `= true`
- [`on c i s`]t `=` [`s`]t' if [`c`]t `= false` where t' is the greatest t' < t with [`c`]t' `= true`.
- [`on c i s`]t `=` `i` otherwise.

    val when_ : ?eq:('a -> 'a -> bool) ->
           bool React.signal -> 'a -> 'a React.signal -> 'a React.signal

Deprecated.Use `React.S.on`.

    val dismiss : ?eq:('a -> 'a -> bool) ->
           'b React.event -> 'a -> 'a React.signal -> 'a React.signal

`dismiss c i s` is the signal `s` except changes when `c` occurs are ignored. If `c` occurs initially `i` is used.

- [`dismiss c i s`]t `=` [`s`]t' where t' is the greatest t' <= t with [`c`]t' `= None` and [`s`]t'-dt `<>` [`s`]t'
- [`dismiss_ c i s`]0 `=` `v` where `v = i` if [`c`]0 `= Some _` and `v =` [`s`]0 otherwise.

# Accumulating

    val accum : ?eq:('a -> 'a -> bool) -> ('a -> 'a) React.event -> 'a -> 'a React.signal

`accum e i` is `S.hold i (``React.E.accum` `e i)`.

    val fold : ?eq:('a -> 'a -> bool) ->
           ('a -> 'b -> 'a) -> 'a -> 'b React.event -> 'a React.signal

`fold f i e` is `S.hold i (``React.E.fold` `f i e)`.

# Combining

    val merge : ?eq:('a -> 'a -> bool) ->
           ('a -> 'b -> 'a) -> 'a -> 'b React.signal list -> 'a React.signal

`merge f a sl` merges the value of every signal in `sl` using `f` and the accumulator `a`.

[`merge f a sl`]t `= List.fold_left f a (List.map` []t`sl)`.

    val switch : ?eq:('a -> 'a -> bool) -> 'a React.signal React.signal -> 'a React.signal

`switch ss` is the inner signal of `ss`.

- [`switch ss`]t `=` [[`ss`]t]t.

    val bind : ?eq:('b -> 'b -> bool) ->
           'a React.signal -> ('a -> 'b React.signal) -> 'b React.signal

`bind s sf` is `switch (map ~eq:( == ) sf s)`.

    val fix : ?eq:('a -> 'a -> bool) ->
           'a -> ('a React.signal -> 'a React.signal * 'b) -> 'b

`fix i sf` allow to refer to the value a signal had an infinitesimal amount of time before.

In `fix sf`, `sf` is called with a signal `s` that represents the signal returned by `sf` delayed by an infinitesimal amount time. If `s', r = sf s` then `r` is returned by `fix` and `s` is such that :

- [`s`]t `=` `i` for t = 0.
- [`s`]t `=` [`s'`]t-dt otherwise.

`eq` is the equality used by `s`.

Raises. `Invalid_argument` if `s'` is directly a delayed signal (i.e. a signal given to a fixing function).

Note. Regarding values depending on the result `r` of `s', r = sf s` the following two cases need to be distinguished :

- After `sf s` is applied, `s'` does not depend on a value that is in a step and `s` has no dependents in a step (e.g in the simple case where `fix` is applied outside a step).

  In that case if the initial value of `s'` differs from `i`, `s` and its dependents need to be updated and a special update step will be triggered for this. Values depending on the result `r` will be created only after this special update step has finished (e.g. they won't see the `i` of `s` if `r = s`).

- Otherwise, values depending on `r` will be created in the same step as `s` and `s'` (e.g. they will see the `i` of `s` if `r = s`).

# Lifting

Lifting combinators. For a given `n` the semantics is :

[`ln f a1` ... `an`]t = f [`a1`]t ... [`an`]t

    val l1 : ?eq:('b -> 'b -> bool) -> ('a -> 'b) -> 'a React.signal -> 'b React.signal

    val l2 : ?eq:('c -> 'c -> bool) ->
           ('a -> 'b -> 'c) -> 'a React.signal -> 'b React.signal -> 'c React.signal

    val l3 : ?eq:('d -> 'd -> bool) ->
           ('a -> 'b -> 'c -> 'd) ->
           'a React.signal -> 'b React.signal -> 'c React.signal -> 'd React.signal

    val l4 : ?eq:('e -> 'e -> bool) ->
           ('a -> 'b -> 'c -> 'd -> 'e) ->
           'a React.signal ->
           'b React.signal -> 'c React.signal -> 'd React.signal -> 'e React.signal

    val l5 : ?eq:('f -> 'f -> bool) ->
           ('a -> 'b -> 'c -> 'd -> 'e -> 'f) ->
           'a React.signal ->
           'b React.signal ->
           'c React.signal -> 'd React.signal -> 'e React.signal -> 'f React.signal

    val l6 : ?eq:('g -> 'g -> bool) ->
           ('a -> 'b -> 'c -> 'd -> 'e -> 'f -> 'g) ->
           'a React.signal ->
           'b React.signal ->
           'c React.signal ->
           'd React.signal -> 'e React.signal -> 'f React.signal -> 'g React.signal

The following modules lift some of `Pervasives` functions and operators.

    module Bool: sig .. end

    module Int: sig .. end

    module Float: sig .. end

    module Pair: sig .. end

    module Option: sig .. end

    module Compare: sig .. end

# Combinator specialization

Given an equality function `equal` and a type `t`, the functor `React.S.Make` automatically applies the `eq` parameter of the combinators. The outcome is combinators whose results are signals with values in `t`.

Basic types are already specialized in the module `React.S.Special`, open this module to use them.

    module type EqType = sig .. end

Input signature of `React.S.Make`

    module type S = sig .. end

Output signature of `React.S.Make`

    module Make: functor (Eq : EqType) -> S  with type 'a v = 'a Eq.t

Functor specializing the combinators for the given signal value type

    module Special: sig .. end

Specialization for booleans, integers and floats.