-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathreactiveData.mli
More file actions
247 lines (185 loc) · 8.65 KB
/
Copy pathreactiveData.mli
File metadata and controls
247 lines (185 loc) · 8.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
(* ReactiveData
* https://github.com/ocsigen/reactiveData
* Copyright (C) 2014 Hugo Heuzard
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, with linking exception;
* either version 2.1 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*)
(** ReactiveData is a module for data-aware functional reactive
programming (FRP). It adds support to incremental changes in data
structures by reasoning on patches instead of absolute
values. ReactiveData is based on and inter-operates with React.
You are most likely interested in the sub-module [RList], which
implements a superset of the signature [S]. *)
(** Signature describing a reactive data structure (['a t]).
Most functions in [S] are not safe to call during a React update
step. *)
module type S = sig
(** Reactive version of the data container *)
(** Raw (non-reactive) version of the data container *)
type 'a data
(** Patch format *)
type 'a patch
(** Message format *)
type 'a msg =
| Patch of 'a patch (** [Patch p] triggers the application of [p]
on the current contents *)
| Set of 'a data (** With [Set d], [d] becomes the new
content *)
type 'a t
(** Handle that permits applying incremental updates *)
type 'a handle
(** Empty data structure *)
val empty : 'a t
(** Build a container from initial contents. The handle can be used
for performing reactive updates. *)
val create : 'a data -> 'a t * 'a handle
(** [from_event d e] is a container whose initial value is [d], and
which gets updated for every occurrence of [e] *)
val from_event : 'a data -> 'a msg React.E.t -> 'a t
(** Convert a React signal into a ReactiveData container.
Whenever the signal changes from value [v] to value [v'], we
detect the differences between [v] and [v'], and perform
downstream computation (e.g., for [map]) only on the new and
modified elements. *)
val from_signal :
?eq:('a -> 'a -> bool) -> 'a data React.S.t -> 'a t
(** Produce a constant container *)
val const : 'a data -> 'a t
(** [patch h p] applies [p] on the container corresponding to [h] *)
val patch : 'a handle -> 'a patch -> unit
(** [set h d] sets the contents of the container corresponding to
[h], disregarding previous contents *)
val set : 'a handle -> 'a data -> unit
(** Transform a message *)
val map_msg : ('a -> 'b) -> 'a msg -> 'b msg
(** [map f c] applies [f] on all elements of [c], producing a new
reactive container [c']. Modifying the contents of [c] leads to
modifications of [c']. [f] is applied only on the new or
modified elements of [c]. *)
val map : ('a -> 'b) -> 'a t -> 'b t
(** Return current contents *)
val value : 'a t -> 'a data
(** [fold f c v] accumulates the updates on [c] with [f] starting
from [v].
The result is a signal of value [f m_n (f ... (f m_1 v))], where
[m_1] ... [m_n] are the messages that have been applied since
the beginning of [fold]. [m_1] is a pseudo-message [Set l],
accounting for the contents [l] of [c] at the time when
accumulation starts. *)
val fold : ('a -> 'b msg -> 'a) -> 'b t -> 'a -> 'a React.signal
(** Signal corresponding to contents *)
val signal :
?eq:('a -> 'a -> bool) -> 'a t -> 'a data React.S.t
(** Event whose occurrences correspond to container updates *)
val event : 'a t -> 'a msg React.E.t
end
(** Reactive list data structure *)
module RList :
sig
(** Patch operation on lists. All operations are of linear
complexity. *)
type 'a p =
| I of int * 'a (** [I (i, v)] adds [v] at position [i] *)
| R of int (** [R i] removes [i]-th element *)
| U of int * 'a (** [U (i, v)] substitutes [i]-th element with [v] *)
| X of int * int (** [X (i, j)] swaps the [i]-th and [j]-th elements *)
(** A patch is a list of patch operations. The operations are
applied in the order they appear in the list.
The indices correspond to list contents after the operations
that appear earlier in the list have been applied, not to the
contents before the whole patch operation.
A patch comprised of [I], [R], and [U] steps with increasing
indices can be applied in time O(m + n), where m is the patch
length and n is the current size of the list. (Arbitrary patches
are slower, requiring O(m * n).) *)
type 'a patch = 'a p list
include S with type 'a data = 'a list
and type 'a patch := 'a patch
(** Add element to the beginning *)
val cons : 'a -> 'a handle -> unit
(** Add element to the end *)
val snoc : 'a -> 'a handle -> unit
(** [insert v i h] adds [v] as the [i]-th position in the container
corresponding to [h]. The indices of the subsequent elements
change. *)
val insert : 'a -> int -> 'a handle -> unit
(** [remove i h] removes the [i]-th position from the container
corresponding to [h]. The indices of the subsequent elements
change. *)
val remove : int -> 'a handle -> unit
(** [remove_last a] removes the last element of [a] *)
val remove_last : ('a t * 'a handle) -> unit
(** [remove_eq l x] removes the first occurence of [x] from [l] *)
val remove_eq : ?eq:('a -> 'a -> bool) -> ('a t * 'a handle) -> 'a -> unit
(** [update v i h] substitutes the [i]-th element of the container
corresponding to [h] with [v] *)
val update : 'a -> int -> 'a handle -> unit
(** [update_eq l a b] substitutes the first occurence of [a] (according to [eq])
in [l] with [b] *)
val update_eq : ?eq:('a -> 'a -> bool) -> ('a t * 'a handle) -> 'a -> 'a -> unit
(** [move i offset h] moves the [i]-th element of the container
corresponding by [offset] positions in [h], modifying the
indices of other elements *)
val move : int -> int -> 'a handle -> unit
(** Produce container list containing a single, constant element *)
val singleton : 'a -> 'a t
val filter : ('a -> bool) -> 'a t -> 'a t
(** Produce reactive list containing a single element that gets
updated based on a signal *)
val singleton_s : 'a React.S.t -> 'a t
(** [concat a b] is the concatenation of [a] and [b], and it gets
updated whenever [a] and [b] change *)
val concat : 'a t -> 'a t -> 'a t
(** [rev a] is the reversal of [a]; [rev a] gets updated along with
[a] *)
val rev : 'a t -> 'a t
(** [for_all fn l] is a [bool React.S.t] verifying that all elements [x] of [l]
satisfy [fn x] *)
val for_all : ('a -> bool) -> 'a t -> bool React.S.t
end
(** Reactive map data structure *)
module RMap(M : Map.S) : S
with type 'a data = 'a M.t
and type 'a patch = [ `Add of M.key * 'a | `Del of M.key ] list
(** Signature describing a raw data container (['a data]).
Given an implementation of [DATA], an incremental version of the
container can be produced (via [Make]). *)
module type DATA = sig
(** Data container *)
type 'a data
(** Patch format for modifying the container *)
type 'a patch
(** Applicative merge operation: [merge p d] is a new container
produced by applying [p] on [d]. [d] does not change. *)
val merge : 'a patch -> 'a data -> 'a data
(** Transform a patch *)
val map_patch : ('a -> 'b) -> 'a patch -> 'b patch
(** [map f d] applies [f] on all the elements of [d], producing a
new container in an applicative way *)
val map_data : ('a -> 'b) -> 'a data -> 'b data
(** Empty container *)
val empty : 'a data
(** Lift an equality operator over atoms of type ['a] to an equality
operator over ['a data] *)
val equal : ('a -> 'a -> bool) -> 'a data -> 'a data -> bool
(** [diff ?eq d1 d2] produces a patch describing the differences
between [d1] and [d2].
The optional [?eq] argument is used for comparing the atoms
inside [d1] and [d2]. (The default value for [eq] is [(=)].) *)
val diff : eq:('a -> 'a -> bool) -> 'a data -> 'a data -> 'a patch
end
(** Functor for turning a plain container into an incremental one *)
module Make(D : DATA) : S with type 'a data = 'a D.data
and type 'a patch = 'a D.patch