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 * ('a -> unit)

`create i` is a primitive signal `s` set to `i` and a `set` function. `set v` sets the signal's value to `v` at the time it is called and triggers an update cycle.

Warning. `send` must not be executed inside an update cycle.

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

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

Warning. If executed in an update cycle 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 : '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.

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

    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 when_ : ?eq:('a -> 'a -> bool) ->
           bool React.signal -> 'a -> 'a React.signal -> 'a React.signal

`when_ 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.

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

    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 -> 'a React.signal React.event -> 'a React.signal

`switch s es` is `s` until there is an occurrence `s'` on `es`, `s'` is then used until there is a new occurrence on `es`, etc..

- [`switch s es`]t `=` [`s`]t if [`es`]<=t `= None`.
- [`switch s es`]t `=` [`s'`]t if [`es`]<=t `= Some 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 cycle and `s` has no dependents in a cycle (e.g in the simple case where `fix` is applied outside a cycle).

  In that case if the initial value of `s'` differs from `i`, `s` and its dependents need to be updated and a special update cycle will be triggered for this. Values depending on the result `r` will be created only after this special update cycle 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 cycle 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 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.