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 fromInit
to a series ofPatch
possibly. The series ofPatch
es may be interspersed withKeep
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 tox'
withdx
holding information about the difference from the current valuex
tox'
.Keep x
announces that the cumulus signal will remain unchanged, wherex
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 valuev
.
val create : 'a -> ('a, 'da) t * (?step:React.Step.t -> ('a, 'da) change -> unit)
create v
is a(v, f)
wherev
is a new cumulus signal starting with the valuev
and which can be updated by callingf
.
val of_event : 'a React.event -> (unit, 'a) t
of_event e
is the cumulus signal having no state and reporting events frome
as its changes.
val of_signal : 'a React.signal -> ('a, unit) t
of_signal s
is a cumulus signal holding the same value ass
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 atv
, then taking values frome
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 withv
then for each occurrencedx
ofe
, then signal is updated byf dx
withdx
reported as the change.
Stopping
val stop : ?strong:bool -> ('a, 'da) t -> unit
stop c
changesc
into a constant cumulus signal holding the latest value. Thestrong
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 ofc
. 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 asc
at any time.
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