# Module `Cumulus`

Differential Signals

`type ('a, 'da) t`
`type ('a, 'da) change`` = `
 `| ``Init of 'a` an initial value of a cumulus signal `| ``Patch of 'a * 'da` the latest value and change of a cumulus signal `| ``Keep of 'a` the latest value of an unmodified signal

`('a, 'da) change` represents the value and latest change of a cumulus signal. Normally a signal goes from `Init` to a series of `Patch` possibly. The series of `Patch`es may be interspersed with `Keep` for functions which observe the signal between its changes.

`Init` may also occur later in the series for some cumulus signals and indicates that it has been reinitialized. Such a cumulus signals are said to be discontinuous.

`type ('a, 'da) update`` = 'a -> ('a, 'da) change`

A shortcut for the function type used to represent updates to a cumulus signal. The function takes the current value of the signal and the result indicates the next value and how it changed from the current value. `Patch (x', dx)` announces that the value changed to `x'` with `dx` holding information about the difference from the current value `x` to `x'`. `Keep x` announces that the cumulus signal will remain unchanged, where `x` must be the argument to the update function. `Init x'` can be used to reinitialize the cumulus signal, introducing a discontinuity.

## Construction and Integration

`val const : 'a -> ('a, 'da) t`

`const v` is the cumulus signal holding the constant value `v`.

`val create : 'a -> ('a, 'da) t * (?⁠step:React.Step.t -> ('a, 'da) change -> unit)`

`create v` is a `(v, f)` where `v` is a new cumulus signal starting with the value `v` and which can be updated by calling `f`.

`val of_event : 'a React.event -> (unit, 'a) t`

`of_event e` is the cumulus signal having no state and reporting events from `e` as its changes.

`val of_signal : 'a React.signal -> ('a, unit) t`

`of_signal s` is a cumulus signal holding the same value as `s` at any time while providing no differential information about the changes.

`val hold : 'a -> 'a React.event -> ('a, unit) t`

`hold v e` is the cumulus signal starting at `v`, then taking values from `e` while providing no differential information about the changes.

`val integrate : ('da -> 'a -> 'a) -> 'da React.event -> 'a -> ('a, 'da) t`

`integrate f e v` is the cumulus signal starting off with `v` then for each occurrence `dx` of `e`, then signal is updated by `f dx` with `dx` reported as the change.

`val fold : ('b -> ('a, 'da) update) -> 'b React.event -> 'a -> ('a, 'da) t`

## Stopping

`val stop : ?⁠strong:bool -> ('a, 'da) t -> unit`

`stop c` changes `c` into a constant cumulus signal holding the latest value. The `strong` parameter is relevant for platforms which don't have weak references. See the React library for details.

## Observation

`val value : ('a, 'da) t -> 'a`

`value c` is the currently held value of `c`. This should not be called during an update step.

`val signal : ('a, 'da) t -> 'a React.signal`

`signal c` is the react signal holding the same value as `c` at any time.

`val changes : ('a, 'da) t -> ('a, 'da) change React.event`
`val trace : (('a, 'da) change -> unit) -> ('a, 'da) t -> ('a, 'da) t`

## Full Lifting

`val lift1 : init:('a -> 'b) -> patch:(('a, 'da) change -> ('b, 'db) update) -> ('a, 'da) t -> ('b, 'db) t`
`val lift2 : init:('a -> 'b -> 'c) -> patch:(('a, 'da) change -> ('b, 'db) change -> ('c, 'dc) update) -> ('a, 'da) t -> ('b, 'db) t -> ('c, 'dc) t`
`val lift3 : init:('a -> 'b -> 'c -> 'd) -> patch:(('a, 'da) change -> ('b, 'db) change -> ('c, 'dc) change -> ('d, 'dd) update) -> ('a, 'da) t -> ('b, 'db) t -> ('c, 'dc) t -> ('d, 'dd) t`

## Simplified Lifting

These functions cover the common case of deriving new cumulus signals from existing ones. This is done by providing a function `~init` which constructs the initial value from the latest values of the source signals, and a function `~patch` which provides an update given the latest values and changes of the source signals. The following example combines two cumulus signals by pairing the values and combining the differentials:

``````let c =
let init x1 x2 = (x1, x2) in
let patch (x1, dx1) (x2, dx2) y =
(match dx1, dx2 with
| None, None -> Cumulus.Keep y
| Some dx1, None -> Cumulus.Patch ((x1, x2), `Left dx1)
| None, Some dx2 -> Cumulus.Patch ((x1, x2), `Right dx2)
| Some dx1, Some dx2 -> Cumulus.Patch ((x1, x2), `Both (dx1, dx2)))
in
Cumulus.l2 ~init ~patch c1 c2``````

The main difference from full lifting is that a discontinuity of any of the source signals will cause a discontinuity in the constructed signal, meaning that `~init` will be called instead of `~patch`, which for the common case of continuous cumulus signals makes no difference.

`val l1 : init:('a -> 'b) -> patch:(('a * 'da) -> ('b, 'db) update) -> ('a, 'da) t -> ('b, 'db) t`
`val l2 : init:('a -> 'b -> 'c) -> patch:(('a * 'da option) -> ('b * 'db option) -> ('c, 'dc) update) -> ('a, 'da) t -> ('b, 'db) t -> ('c, 'dc) t`
`val l3 : init:('a -> 'b -> 'c -> 'd) -> patch:(('a * 'da option) -> ('b * 'db option) -> ('c * 'dc option) -> ('d, 'dd) update) -> ('a, 'da) t -> ('b, 'db) t -> ('c, 'dc) t -> ('d, 'dd) t`
`val l4 : init:('a -> 'b -> 'c -> 'd -> 'e) -> patch:(('a * 'da option) -> ('b * 'db option) -> ('c * 'dc option) -> ('d * 'dd option) -> ('e, 'de) update) -> ('a, 'da) t -> ('b, 'db) t -> ('c, 'dc) t -> ('d, 'dd) t -> ('e, 'de) t`
`val l5 : init:('a -> 'b -> 'c -> 'd -> 'e -> 'f) -> patch:(('a * 'da option) -> ('b * 'db option) -> ('c * 'dc option) -> ('d * 'dd option) -> ('e * 'de option) -> ('f, 'df) update) -> ('a, 'da) t -> ('b, 'db) t -> ('c, 'dc) t -> ('d, 'dd) t -> ('e, 'de) t -> ('f, 'df) t`
`val l6 : init:('a -> 'b -> 'c -> 'd -> 'e -> 'f -> 'g) -> patch:(('a * 'da option) -> ('b * 'db option) -> ('c * 'dc option) -> ('d * 'dd option) -> ('e * 'de option) -> ('f * 'df option) -> ('g, 'dg) update) -> ('a, 'da) t -> ('b, 'db) t -> ('c, 'dc) t -> ('d, 'dd) t -> ('e, 'de) t -> ('f, 'df) t -> ('g, 'dg) t`
`val lN : init:('a list -> 'b) -> patch:(('a * 'da option) list -> ('b, 'db) update) -> ('a, 'da) t list -> ('b, 'db) t`

## Higher Order

`val bind : ('a, 'da) t -> (('a, 'da) change -> ('b, 'db) t) -> ('b, 'db) t`