Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

doc rewrite

  • Loading branch information...
commit 6996e97ab687469bbad544461d8a19868ffdac34 1 parent dad62d9
authored May 04, 2010
395  src/froc/froc.mli
@@ -23,48 +23,83 @@
23 23
    {2 Overview}
24 24
 
25 25
    [Froc] implements functional reactive programming in the style of
26  
-   FrTime / Flapjax (but typed). It uses the dynamic dependency graph
27  
-   of Acar et al. (self-adjusting computation). Behaviors are
28  
-   presented as monadic values, using ideas from [Lwt].
29  
-
30  
-   A {e behavior} is a monadic value that can change over
31  
-   time. Binding a behavior causes the binder to be made a dependency
32  
-   of the behavior, and to be re-executed when the behavior changes.
33  
-
34  
-   An {e event} is a channel over which values may be sent (using the
35  
-   associated {e event_sender}). Listeners on the channel are notified
36  
-   when an event occurs (i.e. a value is sent on the channel).
37  
-
38  
-   Sent events are queued; after each event in the queue is sent and
39  
-   its listeners notified, the dependency graph is processed to update
40  
-   any affected behaviors in a consistent way.
41  
-
42  
-   When a dependency of a behavior must be re-executed, all resources
43  
-   (i.e. binds and notifies) used in the previous execution are
44  
-   released, and all cleanup functions set in the previous execution
45  
-   are run (see [cleanup]).
  26
+   FrTime / Flapjax (but typed of course). It uses the dynamic
  27
+   dependency graph of Acar et al. (self-adjusting
  28
+   computation). Behaviors are presented as monadic values, using
  29
+   ideas from [Lwt].
  30
+
  31
+   A {e behavior} is a value that can change over time, but is defined
  32
+   at all times. An {e event} is defined only at particular instants
  33
+   in time, with a possibly different value at each instance; when an
  34
+   event takes value [v] we say it {e occurs with value} [v] or {e
  35
+   fires} [v]. Values are sent to an event using the associated {e
  36
+   event sender}. A behavior or an event is a {e signal} when we don't
  37
+   care to specify which one it is, and we say a signal "changes" to
  38
+   mean that it changes if it is a behavior or occurs if it is an
  39
+   event.
  40
+
  41
+   Most of the functions in [Froc] create a new signal from one or
  42
+   more existing signals. The output signals are {e dependents} of the
  43
+   input signals and the inputs are the {e dependencies} of the
  44
+   outputs. When a signal changes, its dependents are updated
  45
+   (according to some update function specific to the signal). The
  46
+   dependencies of a signal are updated before the signal is updated,
  47
+   so that the update function sees a consistent view of the
  48
+   dependencies. Signals may have {e listeners} which are {e notified}
  49
+   when the signal changes. Listeners are like dependents but don't
  50
+   compute new signals; they are just functions, called for their
  51
+   effect.
  52
+
  53
+   When an event is sent (with [send]), an {e update cycle} begins,
  54
+   during which the transitive dependents of the initial event are
  55
+   updated, and their listeners notified. It is not allowed to call
  56
+   [send] again until the update cycle is finished, but
  57
+   [send_deferred] may be called, which queues the event. Queued
  58
+   events are processed (each in a new update cycle) following each
  59
+   update cycle until the queue is empty. Events occurring in the same
  60
+   update cycle are {e simultaneous}.
  61
+
  62
+   The body of a listener or update function (such as the function
  63
+   passed to [bind]) delimits a {e dynamic scope}, which is {e
  64
+   governed} by the signals to which it is attached. When a signal
  65
+   changes, listeners and dependents attached within the dynamic
  66
+   scopes it governs are detached, and any attached [cleanup]
  67
+   functions are called. This cleanup allows unneeded values to be
  68
+   garbage collected, and also prevents them from being recomputed
  69
+   unnecessarily or erroneously. Dynamic scopes are nested; cleaning
  70
+   up an enclosing scope cleans up its enclosed scopes. Attachments
  71
+   created outside any dynamic scope can only be detached by calling
  72
+   [init].
  73
+
  74
+   Ordinarily, the entirety of a dynamic scope is cleaned up when its
  75
+   governing signal changes. A dynamic scope may be partially cleaned
  76
+   up using a {e memo function} (see [memo]). It is possible (though
  77
+   not encouraged) to hold a reference to a signal (by storing it in a
  78
+   [ref], for instance) after it has been detached from its
  79
+   dependencies; a detached signal is not updated when its
  80
+   dependencies change.
  81
+
  82
+   Most functions returning behaviors take an optional [eq] argument,
  83
+   which gives an equality function on the value of the resulting
  84
+   behavior. A behavior's dependents are only updated when the
  85
+   behavior is updated with a value which is not equal (according to
  86
+   the equality function) to the old value. The default equality holds
  87
+   if the values [compare] to [0] (incomparable values are always not
  88
+   equal). It is encouraged that behaviors of the same type always be
  89
+   given the same equality.
46 90
 *)
47 91
 
48  
-val init : unit -> unit
49  
-  (** Initialize the library. Must be called before any other function. *)
  92
+(** Type of values of type ['a] or exception. *)
  93
+type 'a result = Value of 'a | Fail of exn
50 94
 
51 95
 type cancel
52 96
   (** Type of handles to listener registrations. *)
53 97
 
54  
-val no_cancel : cancel
55  
-  (** Dummy cancel. *)
56  
-
57  
-val cancel : cancel -> unit
58  
-  (** Cancels a listener registration using the given handle. *)
59  
-
60 98
 (** {2 Behaviors} *)
61 99
 
62 100
 type 'a behavior
63 101
   (** Type of behaviors of type ['a]. *)
64 102
 
65  
-(** Type of values of type ['a] or exception. *)
66  
-type 'a result = Value of 'a | Fail of exn
67  
-
68 103
 val return : 'a -> 'a behavior
69 104
   (**
70 105
      [return v] is a constant behavior with value [v].
@@ -78,10 +113,8 @@ val fail : exn -> 'a behavior
78 113
 val bind : ?eq:('b -> 'b -> bool) -> 'a behavior -> ('a -> 'b behavior) -> 'b behavior
79 114
   (**
80 115
      [bind b f] behaves as [f] applied to the value of [b]. If [b]
81  
-     fails, [bind b f] also fails, with the same exception.
82  
-
83  
-     When the value of a behavior changes, all functions [f] bound to
84  
-     it are re-executed.
  116
+     fails, [bind b f] also fails, with the same exception. The update
  117
+     function [f] delimits a dynamic scope governed by [b].
85 118
   *)
86 119
 
87 120
 val (>>=) : 'a behavior -> ('a -> 'b behavior) -> 'b behavior
@@ -91,8 +124,8 @@ val (>>=) : 'a behavior -> ('a -> 'b behavior) -> 'b behavior
91 124
 
92 125
 val blift : ?eq:('b -> 'b -> bool) -> 'a behavior -> ('a -> 'b) -> 'b behavior
93 126
   (**
94  
-     [blift b ?eq f] is equivalent to [bind b (fun v -> return ?eq (f
95  
-     v))], but is slightly more efficient.
  127
+     [blift b ?eq f] is equivalent to [bind b (fun v -> return ?eq (f v))],
  128
+     but is slightly more efficient.
96 129
   *)
97 130
 
98 131
 val lift : ?eq:('b -> 'b -> bool) -> ('a -> 'b) -> 'a behavior -> 'b behavior
@@ -115,26 +148,28 @@ val sample_result : 'b behavior -> 'b result
115 148
 
116 149
 val catch : ?eq:('a -> 'a -> bool) -> (unit -> 'a behavior) -> (exn -> 'a behavior) -> 'a behavior
117 150
   (**
118  
-     [catch b f] behaves the same as [b()] if [b()] succeeds. If [b()]
119  
-     fails with some exception [e], [catch b f] behaves as [f e].
  151
+     [catch bf f] behaves the same as [bf()] if [bf()] succeeds. If
  152
+     [bf()] fails with some exception [e], [catch bf f] behaves as [f
  153
+     e]. The function [f] delimits a dynamic scope governed by [bf()].
120 154
   *)
121 155
 
122 156
 val catch_lift : ?eq:('a -> 'a -> bool) -> (unit -> 'a behavior) -> (exn -> 'a) -> 'a behavior
123 157
   (**
124  
-     [catch_lift b ?eq f] is equivalent to [catch b (fun e -> return
  158
+     [catch_lift bf ?eq f] is equivalent to [catch bf (fun e -> return
125 159
      ?eq (f e))], but is slightly more efficient.
126 160
   *)
127 161
 
128 162
 val try_bind : ?eq:('b -> 'b -> bool) -> (unit -> 'a behavior) -> ('a -> 'b behavior) -> (exn -> 'b behavior) -> 'b behavior
129 163
   (**
130  
-     [try_bind b f g] behaves as [bind (b()) f] if [b()] succeeds. If
131  
-     [b()] fails with exception [e], [try_bind b f g] behaves as [g
132  
-     e].
  164
+     [try_bind bf f g] behaves as [bind (bf()) f] if [bf()]
  165
+     succeeds. If [bf()] fails with exception [e], [try_bind b f g]
  166
+     behaves as [g e]. The functions [f] and [g] each delimit a
  167
+     dynamic scope governed by [bf()].
133 168
   *)
134 169
 
135 170
 val try_bind_lift : ?eq:('b -> 'b -> bool) -> (unit -> 'a behavior) -> ('a -> 'b) -> (exn -> 'b) -> 'b behavior
136 171
   (**
137  
-     [try_bind_lift b ?eq f g] is equivalent to [try_bind b (fun v ->
  172
+     [try_bind_lift bf ?eq f g] is equivalent to [try_bind bf (fun v ->
138 173
      return ?eq (f v)) (fun e -> return ?eq (g e))], but is slightly
139 174
      more efficient.
140 175
   *)
@@ -150,20 +185,21 @@ val fix_b : ?eq:('a -> 'a -> bool) -> ('a behavior -> 'a behavior) -> 'a behavio
150 185
 
151 186
 val notify_b : ?current:bool -> 'a behavior -> ('a -> unit) -> unit
152 187
   (**
153  
-     Adds a listener for the value of a behavior, which is called
154  
-     whenever the value changes. When the behavior fails the listener
155  
-     is not called. The notification is implicitly cancelled when the
156  
-     calling context is re-run.
157  
-
  188
+     [notify_b b f] adds [f] as a listener for [b], which is called
  189
+     whenever [b] changes. When [b] fails the listener is not
  190
+     called. The notification is cancelled when the enclosing dynamic
  191
+     scope is cleaned up.
  192
+     
158 193
      The listener is called immediately with the current value of the
159  
-     behavior, unless [current] is false.
  194
+     behavior, unless [current] is false. The function [f] delimits a
  195
+     dynamic scope governed by [b].
160 196
   *)
161 197
 
162 198
 val notify_b_cancel : ?current:bool -> 'a behavior -> ('a -> unit) -> cancel
163 199
   (**
164 200
 
165 201
      Same as [notify_b], and returns a cancel handle (the notification
166  
-     is still implicitly cancelled).
  202
+     is still cancelled when the enclosing dynamic scope is cleaned up).
167 203
   *)
168 204
 
169 205
 val notify_result_b : ?current:bool -> 'a behavior -> ('a result -> unit) -> unit
@@ -174,74 +210,45 @@ val notify_result_b : ?current:bool -> 'a behavior -> ('a result -> unit) -> uni
174 210
 
175 211
 val notify_result_b_cancel : ?current:bool -> 'a behavior -> ('a result -> unit) -> cancel
176 212
   (**
177  
-     Same as [notify_b_cancel], and returns a cancel handle (the notification
178  
-     is still implicitly cancelled).
  213
+     Same as [notify_result_b], and returns a cancel handle (the
  214
+     notification is still cancelled when the enclosing dynamic scope
  215
+     is cleaned up).
179 216
   *)
180 217
 
181  
-val cleanup : (unit -> unit) -> unit
182  
-  (**
183  
-     When called in the context of a binder, adds a function to be
184  
-     called when the binder must be re-executed. You can use this to
185  
-     clean up external resources.
186  
-
187  
-     Binds and notifies in the context of a binder are cleaned up
188  
-     automatically.
189  
-  *)
190  
-
191  
-val memo :
192  
-  ?size:int -> ?hash:('a -> int) -> ?eq:('a -> 'a -> bool) -> unit ->
193  
-  ('a -> 'b) ->
194  
-  ('a -> 'b)
  218
+val hash_behavior : 'a behavior -> int
195 219
   (**
196  
-     [memo f] creates a {e memo function} from [f]. Calls to the memo
197  
-     function are memoized and may be reused when the calling context
198  
-     is re-executed.
199  
-
200  
-     [memo] does not provide general-purpose memoization; calls may be
201  
-     reused only within the calling context in which they originally
202  
-     occurred, and only in the original order they occurred.
203  
-
204  
-     To memoize a recursive function, use the following idiom: {[
205  
-       let m = memo () in
206  
-       let rec f x = ... memo f y in
207  
-       let f x = memo f x
208  
-     ]}
209  
-
210  
-     The default hash function is not appropriate for behaviors and
211  
-     events (since they contain mutable data) so you should use
212  
-     [hash_behavior] and [hash_event] instead.
  220
+     A hash function for behaviors. [Hashtbl.hash] is not appropriate
  221
+     because behaviors contain mutable data.
213 222
   *)
214 223
 
215  
-val hash_behavior : 'a behavior -> int
216  
-  (** A hash function for behaviors, *)
217  
-
218  
-
219 224
 (** {2 Events} *)
220 225
 
221 226
 type +'a event
222  
-  (** Type of events of type ['a]. *)
  227
+  (** Type of events taking values of type ['a]. *)
223 228
 
224 229
 type -'a event_sender
225  
-  (** Type of event senders of type ['a]. *)
  230
+  (** Type of event senders sending values of type ['a]. *)
226 231
 
227 232
 val make_event : unit -> 'a event * 'a event_sender
228  
-  (** Makes a new channel for events of type ['a]. *)
  233
+  (** Makes a new event taking values of type ['a]. *)
229 234
 
230 235
 val never : 'a event
231 236
   (** An event which never occurs. *)
232 237
 
233 238
 val notify_e : 'a event -> ('a -> unit) -> unit
234 239
   (**
235  
-     Adds a listener on the channel, which is called whenever a value
236  
-     is sent on it. When a failure is sent the listener is not
237  
-     called. The notification is implicitly cancelled when the calling
238  
-     context is re-run.
  240
+     [notify_e e f] adds [f] as a listener for [e], which is called
  241
+     with [v] whenever [e] occurs with value [v].  When a failure
  242
+     occurs the listener is not called. The notification is cancelled
  243
+     when the enclosing dynamic scope is cleaned up.
  244
+
  245
+     The function [f] delimits a dynamic scope governed by [b].
239 246
   *)
240 247
 
241 248
 val notify_e_cancel : 'a event -> ('a -> unit) -> cancel
242 249
   (**
243 250
      Same as [notify_e], and returns a cancel handle (the notification
244  
-     is still implicitly cancelled).
  251
+     is still cancelled when the enclosing dynamic scope is cleaned up).
245 252
   *)
246 253
 
247 254
 val notify_result_e : 'a event -> ('a result -> unit) -> unit
@@ -252,73 +259,125 @@ val notify_result_e : 'a event -> ('a result -> unit) -> unit
252 259
 
253 260
 val notify_result_e_cancel : 'a event -> ('a result -> unit) -> cancel
254 261
   (**
255  
-     Same as [notify_e_cancel], and returns a cancel handle (the notification
256  
-     is still implicitly cancelled).
  262
+     Same as [notify_result_e], and returns a cancel handle (the
  263
+     notification is still cancelled when the enclosing dynamic scope
  264
+     is cleaned up).
257 265
   *)
258 266
 
259 267
 val send : 'a event_sender -> 'a -> unit
260  
-  (** [send e v] calls the listeners of the associated event with [Value v]. *) 
  268
+  (**
  269
+     [send s v] sends the value [v] to the associated event [e], so
  270
+     [e] occurs with value [v].
  271
+  *)
261 272
 
262 273
 val send_exn : 'a event_sender -> exn -> unit
263  
-  (** [send_exn e x] calls the listeners of the associated event with [Fail x]. *) 
  274
+  (**
  275
+     [send_exn s x] sends the failure [x] to the associated event [e],
  276
+     so [e] occurs with failure [x].
  277
+  *) 
264 278
 
265 279
 val send_result : 'a event_sender -> 'a result -> unit
266  
-  (** [send_result e r] calls the listeners of the associated event with [r]. *)
  280
+  (**
  281
+     [send_result s r] sends the result [r] to the associated event
  282
+     [e], so [e] occurs with result [r].
  283
+  *)
267 284
 
268 285
 val send_deferred : 'a event_sender -> 'a -> unit
269  
-  (** [send e v] calls the listeners of the associated event with [Value v] in the next update cycle. *) 
  286
+  (**
  287
+     [send_deferred s v] enqueues a call to [send s v] for a future
  288
+     update cycle.
  289
+  *) 
270 290
 
271 291
 val send_exn_deferred : 'a event_sender -> exn -> unit
272  
-  (** [send_exn e x] calls the listeners of the associated event with [Fail x] in the next update cycle. *) 
  292
+  (**
  293
+     [send_exn_deferred s x] enqueues a call to [send_exn s x] for a
  294
+     future update cycle.
  295
+  *) 
273 296
 
274 297
 val send_result_deferred : 'a event_sender -> 'a result -> unit
275  
-  (** [send_result e r] calls the listeners of the associated event with [r] in the next update cycle. *)
  298
+  (**
  299
+     [send_result_deferred s r] enqueues a call to [send_result s r]
  300
+     for a future update cycle.
  301
+  *)
276 302
 
277 303
 val next : 'a event -> 'a event
278  
-  (** [next e] fires just the next occurence of [e]. *)
  304
+  (**
  305
+     [next e] passes on only the next occurence of [e]; subsequent
  306
+     occurrences are dropped.
  307
+  *)
279 308
 
280 309
 val merge : 'a event list -> 'a event
281  
-  (** [merge es] is an event that fires whenever any of the events in [e] fire. *)
  310
+  (**
  311
+     [merge es] occurs whenever any of the events in [es] occurs. If
  312
+     more than one of the [es] occurs simultaneously, the earliest one
  313
+     in the list is passed on.
  314
+  *)
282 315
 
283 316
 val map : ('a -> 'b) -> 'a event -> 'b event
284  
-  (** [map f e] is an event that fires [f v] whenever [e] fires [v]. *)
  317
+  (**
  318
+     [map f e] is an event that fires [f v] whenever [e] fires
  319
+     [v]. The function [f] delimits a dynamic scope governed by [e].
  320
+  *)
285 321
 
286 322
 val filter : ('a -> bool) -> 'a event -> 'a event
287  
-  (** [filter p e] is an event that fires [v] whenever [e] fires [v] and [p v] is true. *)
  323
+  (**
  324
+     [filter p e] is an event that fires [v] whenever [e] fires [v]
  325
+     and [p v] is true. The function [p] delimits a dynamic scope
  326
+     governed by [e].
  327
+  *)
288 328
 
289 329
 val collect : ('b -> 'a -> 'b) -> 'b -> 'a event -> 'b event
290 330
   (**
291 331
      [collect f b e] is an event that maintains an internal state [s]
292 332
      (initialized to [b]); whenever [e] fires [v], [s'] becomes [f s
293 333
      v], the event fires [s'], and [s'] becomes the new internal
294  
-     state.
  334
+     state. The function [f] delimits a dynamic scope governed by [e].
  335
+
  336
+     Special care must be taken when using [collect] with behavior- or
  337
+     event-valued events. The dynamic scope delimited by [f] is
  338
+     cleaned up on each occurrence of [e]; any signals or created in
  339
+     [f] become detached on the next occurrence, so it is easy to wind
  340
+     up with detached signals in [s].
  341
+
  342
+     This cleanup may be controlled through the use of [memo].
295 343
   *)
296 344
 
297 345
 val join_e : 'a event event -> 'a event
298  
-  (** [join_e ee] fires whenever the event last fired from [ee] fires *)
  346
+  (**
  347
+     [join_e ee] occurs whenever the event which last occurred on [ee]
  348
+     occurs.
  349
+  *)
299 350
 
300 351
 val fix_e : ('a event -> 'a event) -> 'a event
301 352
   (**
302  
-     [fix_e ef] returns [ef e'] where [e'] is an event that fires
303  
-     whenever [ef e'] fires, but in the next update cycle.
  353
+     [fix_e ef] returns [ef e'] where [e'] is an event that occurs
  354
+     whenever [ef e'] occurs, but in the next update cycle.
304 355
   *)
305 356
 
306 357
 val hash_event : 'a event -> int
307  
-  (** A hash function for events. *)
  358
+  (**
  359
+     A hash function for events. [Hashtbl.hash] is not appropriate
  360
+     because events contain mutable data.
  361
+  *)
308 362
 
309  
-(** {2 Combinations of behaviors and events} *)
  363
+(** {2 Combinations} *)
310 364
 
311 365
 val switch : ?eq:('a -> 'a -> bool) -> 'a behavior -> 'a behavior event -> 'a behavior
312  
-  (** [switch b e] behaves as [b] until [e] fires, then behaves as the last value of [e]. *)
  366
+  (**
  367
+     [switch b e] behaves as [b] until [e] occurs, then behaves as the
  368
+     last value of [e].
  369
+  *)
313 370
 
314 371
 val until : ?eq:('a -> 'a -> bool) -> 'a behavior -> 'a behavior event -> 'a behavior
315  
-  (** [until b e] behaves as [b] until [e] fires [b'], then behaves as [b'] *)
  372
+  (**
  373
+     [until b e] behaves as [b] until [e] occurs with value [b'], then
  374
+     behaves as [b'].
  375
+  *)
316 376
 
317 377
 val hold : ?eq:('a -> 'a -> bool) -> 'a -> 'a event -> 'a behavior
318 378
   (**
319  
-     [hold v e] behaves as the last value fired by [e], or [v] if [e]
320  
-     has not yet fired a value (since [hold] was called). [eq]
321  
-     gives the equality on the resulting behavior.
  379
+     [hold v e] takes on the last value which occurred on [e], or
  380
+     [v] if [e] has not yet occurred (since [hold] was called).
322 381
   *)
323 382
 
324 383
 val hold_result : ?eq:('a -> 'a -> bool) -> 'a result -> 'a event -> 'a behavior
@@ -327,14 +386,16 @@ val hold_result : ?eq:('a -> 'a -> bool) -> 'a result -> 'a event -> 'a behavior
327 386
   *)
328 387
 
329 388
 val changes : 'a behavior -> 'a event
330  
-  (** [changes b] fires the value of [b] whenever it changes. *)
  389
+  (**
  390
+     [changes b] occurs with the value of [b] whenever [b] changes.
  391
+  *)
331 392
 
332 393
 val when_true : bool behavior -> unit event
333 394
   (** [when_true b] fires whenever [b] becomes true. *)
334 395
 
335 396
 val count : 'a event -> int behavior
336 397
   (**
337  
-     [count e] behaves as the number of times [e] has fired (since
  398
+     [count e] takes on the number of times [e] has occurred (since
338 399
      [count] was called).
339 400
   *)
340 401
 
@@ -342,15 +403,84 @@ val make_cell : 'a -> 'a behavior * ('a -> unit)
342 403
   (**
343 404
      [make_cell v] returns a behavior (with initial value [v]) and a
344 405
      setter function which changes the behavior's value. The setter
345  
-     respects the update cycle (it enqueues an event) so may be used
  406
+     enqueues the update for a future update cycle, so it may be used
346 407
      freely.
347 408
   *)
348 409
 
349  
-(** {2 Variations} *)
  410
+(** {2 Other} *)
350 411
 
351  
-val bindN : ?eq:('b -> 'b -> bool) -> 'a behavior list -> ('a list -> 'b behavior) -> 'b behavior
352  
-val bliftN : ?eq:('b -> 'b -> bool) -> 'a behavior list -> ('a list -> 'b) -> 'b behavior
353  
-val liftN : ?eq:('b -> 'b -> bool) -> ('a list -> 'b) -> 'a behavior list -> 'b behavior
  412
+val init : unit -> unit
  413
+  (** Initialize the library; can be called again to reinitialize. *)
  414
+
  415
+val no_cancel : cancel
  416
+  (** Dummy cancel. *)
  417
+
  418
+val cancel : cancel -> unit
  419
+  (** Cancels a listener registration using the given handle. *)
  420
+
  421
+val cleanup : (unit -> unit) -> unit
  422
+  (**
  423
+     [cleanup f] attaches [f] to the enclosing dynamic scope, so it is
  424
+     called when the scope is cleaned up. This is useful for cleaning
  425
+     up external resources, such as GUI event handlers.
  426
+  *)
  427
+
  428
+val memo :
  429
+  ?size:int -> ?hash:('a -> int) -> ?eq:('a -> 'a -> bool) -> unit ->
  430
+  ('a -> 'b) ->
  431
+  ('a -> 'b)
  432
+  (**
  433
+     [memo f] creates a memo function [f'] from [f]. When [f' x] is
  434
+     called from within an update function, there may be either a hit
  435
+     or a miss. A hit happens when some [f' x'] was called in the
  436
+     previous run of the update function, when [eq x x'], and no later
  437
+     call has already hit (that is, hits must happen in the same order
  438
+     as the calls happened in the previous run). On a miss, [f' x]
  439
+     calls [f x] in a new dynamic scope, and stores its value for
  440
+     possible reuse. On a hit, [f' x] returns the value of the
  441
+     previous call, and any updates necessary to make the value
  442
+     consistent are executed; the dynamic scope of the previous call
  443
+     is {e not} cleaned up (so that the value remains attached to its
  444
+     dependencies).
  445
+
  446
+     The main point of [memo] is to avoid needless recomputation in
  447
+     cases where a computation is governed by some signal but does not
  448
+     actually use the signal's value. For example, in {[
  449
+       let g = memo () fun x -> ... in
  450
+       b >>= fun _ -> g 7
  451
+     ]} the returned behavior is indifferent to the value of
  452
+     [b]. Without [memo] it would be recomputed every time [b]
  453
+     changes; with [memo] it is computed only the first time.
  454
+
  455
+     Because the dynamic scope of the previous call is not cleaned up
  456
+     on a memo hit, [memo] can be used purely to protect signals and
  457
+     listeners from being detached when their governing signals
  458
+     change. See the [quickhull] example for an instance of this use.
  459
+
  460
+     The unit argument makes it possible to memoize a recursive
  461
+     function, using the following idiom: {[
  462
+       let m = memo () in (* creates the memo table *)
  463
+       let rec f x = ... memo f y in
  464
+       let f x = memo f x
  465
+     ]}
  466
+
  467
+     The default hash function is not appropriate for behaviors and
  468
+     events (since they contain mutable data); [hash_behavior] and
  469
+     [hash_event] should be used instead.
  470
+  *)
  471
+
  472
+(** {2 Debugging} *)
  473
+
  474
+val set_exn_handler : (exn -> unit) -> unit
  475
+  (**
  476
+     Set an exception handler which is called on exceptions from
  477
+     listeners.
  478
+  *)
  479
+
  480
+val set_debug : (string -> unit) -> unit
  481
+  (** Set a function for showing library debugging. *)
  482
+
  483
+(** {2 Variations} *)
354 484
 
355 485
 val bind2 :
356 486
   ?eq:('b -> 'b -> bool) ->
@@ -448,13 +578,6 @@ val lift7 :
448 578
   'a1 behavior -> 'a2 behavior -> 'a3 behavior -> 'a4 behavior -> 'a5 behavior -> 'a6 behavior -> 'a7 behavior ->
449 579
   'b behavior
450 580
 
451  
-(** {2 Debugging} *)
452  
-
453  
-val set_exn_handler : (exn -> unit) -> unit
454  
-  (**
455  
-     Set an exception handler which is called on exceptions from
456  
-     notification functions.
457  
-  *)
458  
-
459  
-val set_debug : (string -> unit) -> unit
460  
-  (** Set a function for showing library debugging. *)
  581
+val bindN : ?eq:('b -> 'b -> bool) -> 'a behavior list -> ('a list -> 'b behavior) -> 'b behavior
  582
+val bliftN : ?eq:('b -> 'b -> bool) -> 'a behavior list -> ('a list -> 'b) -> 'b behavior
  583
+val liftN : ?eq:('b -> 'b -> bool) -> ('a list -> 'b) -> 'a behavior list -> 'b behavior
82  src/froc/froc_sa.mli
@@ -26,19 +26,30 @@
26 26
    Acar et al. Changeable values are presented as a monad, using ideas
27 27
    from [Lwt].
28 28
 
29  
-   A {e changeable} is a monadic value that can change over
30  
-   time. Binding a changeable causes the binder to be made a
31  
-   dependency of the changeable, and to be re-executed when the
32  
-   changeable changes. A {e writeable} associated with a changeable is
33  
-   used to change a changeable.
  29
+   A {e changeable} is a value that can change over time. New
  30
+   changeables may be created from existing ones using [bind] or one
  31
+   of its variants. When a changeable changes, the changeables which
  32
+   depend on it are updated by running their update functions
  33
+   (i.e. the function passed to [bind]). The dependencies of a
  34
+   changeable are updated before the changeable is updated, so that
  35
+   the update function sees a consistent view of the dependencies.
34 36
 
35 37
    Self-adjusting computation proceeds in phases: after an initial
36 38
    computation, call [write] to change some inputs, then [propagate]
37 39
    to make the result consistent again.
  40
+
  41
+   Most functions returning changeables take an optional [eq]
  42
+   argument, which gives an equality function on the value of the
  43
+   resulting changeable. A changeable is considered to have changed
  44
+   only when updated with a value which is not equal (according to the
  45
+   equality function) to the old value. The default equality holds if
  46
+   the values [compare] to [0] (incomparable values are always not
  47
+   equal). It is encouraged that changeables of the same type always
  48
+   be given the same equality.
38 49
 *)
39 50
 
40 51
 val init : unit -> unit
41  
-  (** Initialize the library. Must be called before any other function. *)
  52
+  (** Initialize the library; can be called again to reinitialize. *)
42 53
 
43 54
 (** {2 Changeables} *)
44 55
 
@@ -50,12 +61,6 @@ type -'a u
50 61
 val changeable : ?eq:('a -> 'a -> bool) -> 'a -> 'a t * 'a u
51 62
   (**
52 63
      [changeable v] is a changeable with initial value [v].
53  
-
54  
-     The optional [eq] argument gives an equality function; a
55  
-     changeable is considered changed (and its dependencies notified)
56  
-     only if its new value is not [eq] to its old one. The default
57  
-     equality holds iff the values [compare] to [0] (incomparable
58  
-     values are always not equal).
59 64
   *)
60 65
 
61 66
 val return : 'a -> 'a t
@@ -72,9 +77,6 @@ val bind : ?eq:('b -> 'b -> bool) -> 'a t -> ('a -> 'b t) -> 'b t
72 77
   (**
73 78
      [bind c f] behaves as [f] applied to the value of [c]. If [c]
74 79
      fails, [bind c f] also fails, with the same exception.
75  
-
76  
-     When the value of a changeable changes, all functions [f] bound to
77  
-     it are re-executed.
78 80
   *)
79 81
 
80 82
 val (>>=) : 'a t -> ('a -> 'b t) -> 'b t
@@ -97,26 +99,27 @@ val lift : ?eq:('b -> 'b -> bool) -> ('a -> 'b) -> 'a t -> 'b t
97 99
 
98 100
 val catch : ?eq:('a -> 'a -> bool) -> (unit -> 'a t) -> (exn -> 'a t) -> 'a t
99 101
   (**
100  
-     [catch c f] behaves the same as [c()] if [c()] succeeds. If [c()]
101  
-     fails with some exception [e], [catch c f] behaves as [f e].
  102
+     [catch cf f] behaves the same as [cf()] if [cf()] succeeds. If
  103
+     [cf()] fails with some exception [e], [catch cf f] behaves as [f
  104
+     e].
102 105
   *)
103 106
 
104 107
 val catch_lift : ?eq:('a -> 'a -> bool) -> (unit -> 'a t) -> (exn -> 'a) -> 'a t
105 108
   (**
106  
-     [catch_lift c ?eq f] is equivalent to [catch c (fun e -> return
  109
+     [catch_lift cf ?eq f] is equivalent to [catch cf (fun e -> return
107 110
      ?eq (f e))], but is slightly more efficient.
108 111
   *)
109 112
 
110 113
 val try_bind : ?eq:('b -> 'b -> bool) -> (unit -> 'a t) -> ('a -> 'b t) -> (exn -> 'b t) -> 'b t
111 114
   (**
112  
-     [try_bind c f g] behaves as [bind (c()) f] if [c()] succeeds. If
113  
-     [c()] fails with exception [e], [try_bind c f g] behaves as [g
  115
+     [try_bind cf f g] behaves as [bind (cf()) f] if [cf()] succeeds. If
  116
+     [cf()] fails with exception [e], [try_bind cf f g] behaves as [g
114 117
      e].
115 118
   *)
116 119
 
117 120
 val try_bind_lift : ?eq:('b -> 'b -> bool) -> (unit -> 'a t) -> ('a -> 'b) -> (exn -> 'b) -> 'b t
118 121
   (**
119  
-     [try_bind_lift c ?eq f g] is equivalent to [try_bind c (fun v ->
  122
+     [try_bind_lift cf ?eq f g] is equivalent to [try_bind cf (fun v ->
120 123
      return ?eq (f v)) (fun e -> return ?eq (g e))], but is slightly
121 124
      more efficient.
122 125
   *)
@@ -124,9 +127,6 @@ val try_bind_lift : ?eq:('b -> 'b -> bool) -> (unit -> 'a t) -> ('a -> 'b) -> (e
124 127
 val read : 'a t -> 'a
125 128
   (**
126 129
      [read c] returns the value of [c], or raises an exception if [c] fails.
127  
-
128  
-     You shouldn't call [read] in the context of a binder, since you
129  
-     might get a stale result.
130 130
   *)
131 131
 
132 132
 val write : 'a u -> 'a -> unit
@@ -151,22 +151,36 @@ val memo :
151 151
   ('a -> 'b) ->
152 152
   ('a -> 'b)
153 153
   (**
154  
-     [memo f] creates a {e memo function} from [f]. Calls to the memo
155  
-     function are memoized and may be reused when the calling context
156  
-     is re-executed.
157  
-
158  
-     [memo] does not provide general-purpose memoization; calls may be
159  
-     reused only within the calling context in which they originally
160  
-     occurred, and only in the original order they occurred.
161 154
 
162  
-     To memoize a recursive function, use the following idiom: {[
163  
-       let m = memo () in
  155
+     [memo f] creates a memo function [f'] from [f]. When [f' x] is
  156
+     called from within an update function, there may be either a hit
  157
+     or a miss. A hit happens when some [f' x'] was called in the
  158
+     previous run of the update function, when [eq x x'], and no later
  159
+     call has already hit (that is, hits must happen in the same order
  160
+     as the calls happened in the previous run). On a miss, [f' x]
  161
+     calls [f x] and stores its value for possible reuse. On a hit,
  162
+     [f' x] returns the value of the previous call, and any updates
  163
+     necessary to make the value consistent are executed.
  164
+
  165
+     The main point of [memo] is to avoid needless recomputation in
  166
+     cases where a computation is executed in an update function for
  167
+     some changeable, but does not actually use the changeables's
  168
+     value. For example, in {[
  169
+       let g = memo () fun x -> ... in
  170
+       c >>= fun _ -> g 7
  171
+     ]} the returned changeable is indifferent to the value of
  172
+     [c]. Without [memo] it would be recomputed every time [c]
  173
+     changes; with [memo] it is computed only the first time.
  174
+
  175
+     The unit argument makes it possible to memoize a recursive
  176
+     function, using the following idiom: {[
  177
+     let m = memo () in (* creates the memo table *)
164 178
        let rec f x = ... memo f y in
165 179
        let f x = memo f x
166 180
      ]}
167 181
 
168 182
      The default hash function is not appropriate for changeables
169  
-     (since they contain mutable data) so you should use [hash]
  183
+     (since they contain mutable data); [hash] should be used
170 184
      instead.
171 185
   *)
172 186
 

0 notes on commit 6996e97

Please sign in to comment.
Something went wrong with that request. Please try again.