module Sharp_core:sig
..end
More precisely, they are functions taking the time and returning a value of the appropriate type and a new signal which can be used with future times.
Signals are functors, applicative functors and monads. They can be combined
just like any other applicative functors or monads. For example,
map f s1
maps the function f
on the values taken by the signal s1
returning a signal of the results. apply (map f s1) s2
or, more
idiomatically, f <$> s1 <*> s2
applies the function f
on the values taken
by the signals s1
and s2
and returns a signal of the results. Of course,
g <$> s1 <*> s2 <*> s3
will work with a function g
taking three arguments
(and so forth). Finally, you can bind two signals sequentially with the
monadic interface. Say you have a signal s1
returning the time and a
function f
taking the time as an argument and returning a signal of
integers, you can bind both with bind s1 f
or s1 >>= f
to yield a signal
of integers. The monadic bind on signals can be a bit tricky but map
and
apply
should be more than often in most cases.
Signals are useless if they are not connected to the real world somehow.
To input data into a network of signals, you will need the function event
.
It returns a optional signal (i.e. a signal of type 'a option t
, that is, a
signal taking values of type 'a option
together with a function to trigger
the event. Whenever this trigger is called with a value x
, the signal will
take the value Some x
, otherwise it will be None
.
In order to react to events, there are a few functions which roughly work the
same way. The ones you will use the most are react_with
and react
which
is a specialised version of react_with
. react_with
reacts to a signal of
type 'a option t
when it has a value and another "normal signal" and
executes a given function with the values taken by the signals. Here is a
simple example:
let (int_signal, trigger_int) = event () in
react_with int_signal time (fun x t ->
print_endline ("The time is " ^ string_of_float(t)
^ "and the event has been triggered with the value: "
^ string_of_int(x))
)
This module also includes a couple of functions transforming signals. Other
modules provide ways of binding signal networks to the external world, e.g.
reacting to the click of a button.
typetime =
float
type 'a
t
val const : 'a -> 'a t
val time : time t
val map : ('a -> 'b) -> 'a t -> 'b t
val (<$>) : ('a -> 'b) -> 'a t -> 'b t
map
.val pure : 'a -> 'a t
const
.val apply : ('a -> 'b) t -> 'a t -> 'b t
val (<*>) : ('a -> 'b) t -> 'a t -> 'b t
apply
.val lift0 : 'a -> 'a t
val lift : ('a -> 'b) -> 'a t -> 'b t
val lift2 : ('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t
val lift3 : ('a -> 'b -> 'c -> 'd) ->
'a t -> 'b t -> 'c t -> 'd t
val lift4 : ('a -> 'b -> 'c -> 'd -> 'e) ->
'a t ->
'b t -> 'c t -> 'd t -> 'e t
val lift5 : ('a -> 'b -> 'c -> 'd -> 'e -> 'f) ->
'a t ->
'b t ->
'c t -> 'd t -> 'e t -> 'f t
val map_opt : ('a -> 'b) -> 'a option t -> 'b option t
map
on optional signals.val (<$?>) : ('a -> 'b) -> 'a option t -> 'b option t
map_opt
.val apply_opt : ('a -> 'b) option t ->
'a option t -> 'b option t
apply
on optional signals.val (<*?>) : ('a -> 'b) option t ->
'a option t -> 'b option t
apply_opt
.val sequence : 'a t list -> 'a list t
val return : 'a -> 'a t
const
.val join : 'a t t -> 'a t
val bind : 'a t -> ('a -> 'b t) -> 'b t
val (>>=) : 'a t -> ('a -> 'b t) -> 'b t
bind
.val (>>) : 'a t -> 'b t -> 'b t
>>=
but it discards the value of the first signal.val perform : ?force:bool -> 'a t -> ('a -> unit) -> unit
To be precise, the signal could have the same value as before but something
happened upstream. If some signals have been triggered and the signal passed
to perform
somehow depends on it, through calls to map
or apply
for
instance, the function given to perform
will be called.
val perform_state : ?force:bool -> 'a t -> init:'b -> f:('b -> 'a -> 'b) -> unit
val react : 'a option t -> ('a -> unit) -> unit
val react_with : 'a option t -> 'b t -> ('a -> 'b -> unit) -> unit
react
with an additional signal.
This is useful for things like
react_with button_cliked data_signal (fun () data -> (* do something *))
.
val event : unit -> 'a option t * ('a -> unit)
val connected_event : (('a -> unit) -> unit -> unit) ->
'a option t * ('a -> unit) * (unit -> unit)
The first callback takes the trigger function and should return the second
callback to disconnect the event. To make its use clearer, imagine you want
to create a signal which should be triggered automatically when some JS
event occurs. The first callback would be a function starting to listen to
a JS event, calling the trigger function when the event occurs and returning
a callback to destroy the listener when it's called.
val on : 'a option t -> init:'b -> f:('b -> 'a -> 'b) -> 'b t
init
and changing this value based
on the previous one and a value of an optional signal when it takes one.val last : 'a option t -> init:'a -> 'a t
init
if none.val toggle : 'b option t -> init:bool -> bool t
true
and false
each time the given optional signal takes
a value.val count : ?init:int -> 'b option t -> int t
val upon : ?init:'a -> 'c option t -> 'a t -> 'a t
val fold : 'a t -> init:'b -> f:('b -> 'a -> 'b) -> 'b t
It is important to understand that signals are only called when something
happened. It is therefore not continuous.