A lightweight reactive document library.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

200 lines
6.2 KiB

  1. (** {0 Sequence manipulation}
  2. [Lwd_seq] is an ordered collection with a pure interface.
  3. Changes to collections are easy to track.
  4. A collection can be transformed with the usual map, filter and fold
  5. combinators. If the collection is updated, shared elements (in the sense of
  6. physical sharing), the result of the previous transformation will be reused
  7. for these elements.
  8. The book-keeping overhead is O(n) in the number of changes, so O(1) per
  9. element.
  10. *)
  11. type +'a t
  12. type +'a seq = 'a t
  13. (** The type of sequences *)
  14. (** {1 Primitive constructors} *)
  15. val empty : 'a seq
  16. (** A sequence with no element. *)
  17. val element : 'a -> 'a seq
  18. (** A singleton sequence. The physical identity of the element is considered
  19. when reusing previous computations.
  20. If you do:
  21. {[let x1 = element x
  22. let x2 = element x]}
  23. Then [x1] and [x2] are seen as different elements and no sharing will be
  24. done during transformation.
  25. *)
  26. val concat : 'a seq -> 'a seq -> 'a seq
  27. (** Concatenate two sequences into a bigger one.
  28. As for [element], the physical identity of a sequence is considered for
  29. reuse.
  30. *)
  31. (** {1 Looking at sequence contents} *)
  32. type ('a, 'b) view =
  33. | Empty
  34. | Element of 'a
  35. | Concat of 'b * 'b
  36. val view : 'a seq -> ('a, 'a seq) view
  37. (** View how a sequence is defined *)
  38. (** {1 Conversion between sequences, lists and arrays} *)
  39. val transform_list : 'a list -> ('a -> 'b seq) -> 'b seq
  40. (** Produce a sequence by transforming each element of a list and concatenating
  41. all results. *)
  42. val transform_array : 'a array -> ('a -> 'b seq) -> 'b seq
  43. (** Produce a sequence by transforming each element of an array and
  44. concatenating all results. *)
  45. val of_list : 'a list -> 'a seq
  46. (** Produce a sequence from a list *)
  47. val of_array : 'a array -> 'a seq
  48. (** Produce a sequence from an array *)
  49. val to_list : 'a seq -> 'a list
  50. (** Produce a list from a sequence *)
  51. val to_array : 'a seq -> 'a array
  52. (** Produce an array from a sequence *)
  53. (** {1 Balanced variant of sequences *)
  54. module Balanced : sig
  55. (** A variant of the sequence type that guarantees that the depth of a
  56. transformation, measured as the number of nested [concat] nodes, grows in
  57. O(log n) where n is the number of elements in the sequnce.
  58. This is useful to prevent stack overflows and to avoid degenerate cases
  59. where a single element changes, but it is at the end of a linear sequence
  60. of [concat] nodes, thus making the total work O(n).
  61. For instance, in:
  62. {[concat e1 (concat e2 (concat e3 (... (concat e_n))...))]}
  63. If [e_n] changes, the whole spine has to be recomputed.
  64. Using [Balanced.concat], the representation will be re-balanced
  65. internally. Then [Balanced.view] should be used to access the balanced
  66. sequence.
  67. When working with balanced sequences in a transformation pipeline, it is
  68. only useful to balance the first sequence of the pipeline. Derived
  69. sequence will have a depth bounded by the depth of the first one.
  70. *)
  71. type 'a t = private 'a seq
  72. (** Type of balanced sequences *)
  73. val empty : 'a t
  74. val element : 'a -> 'a t
  75. val concat : 'a t -> 'a t -> 'a t
  76. val view : 'a t -> ('a, 'a t) view
  77. end
  78. (** {1 Transforming sequences} *)
  79. (**
  80. All sequences live in [Lwd] monad: if a sequence changes slightly, parts
  81. that have not changed will not be re-transformed.
  82. *)
  83. val fold :
  84. map:('a -> 'b) -> reduce:('b -> 'b -> 'b) -> 'a seq Lwd.t -> 'b option Lwd.t
  85. (** [fold ~map ~reduce] transforms a sequence.
  86. If the sequence is non-empty, the [map] function is applied to element
  87. nodes and the [reduce] function is used to combine transformed concatenated
  88. nodes.
  89. If the sequence is empty, None is returned.
  90. *)
  91. val fold_monoid :
  92. ('a -> 'b) -> 'b Lwd_utils.monoid -> 'a seq Lwd.t -> 'b Lwd.t
  93. (** Like [fold], but reduction and default value are defined by a [monoid] *)
  94. val map :
  95. ('a -> 'b) -> 'a seq Lwd.t -> 'b seq Lwd.t
  96. (** [map f] transforms a sequence by applying [f] to each element. *)
  97. val filter :
  98. ('a -> bool) -> 'a seq Lwd.t -> 'a seq Lwd.t
  99. (** [filter p] transforms a sequence by keeping elements that satisfies [p]. *)
  100. val filter_map :
  101. ('a -> 'b option) -> 'a seq Lwd.t -> 'b seq Lwd.t
  102. (** Filter and map elements at the same time *)
  103. val lift : 'a Lwd.t seq Lwd.t -> 'a seq Lwd.t
  104. (** Remove a layer of [Lwd] inside a sequence. *)
  105. val bind : 'a seq Lwd.t -> ('a -> 'b seq) -> 'b seq Lwd.t
  106. (** Sequence forms a monad too... *)
  107. val monoid : 'a t Lwd_utils.monoid
  108. (** Monoid instance for sequences *)
  109. val lwd_monoid : 'a t Lwd.t Lwd_utils.monoid
  110. (** Monoid instance for reactive sequences *)
  111. (** {1 Low-level interface for observing changes} *)
  112. module Reducer : sig
  113. (* The interface allows to implement incremental sequence transformation
  114. outside of the [Lwd] monad.
  115. Actually, the Lwd functions above are implemented on top of this
  116. interface.
  117. *)
  118. (* A [('a, 'b) reducer] value stores the state necessary to incrementally
  119. transform an ['a seq] to ['b].
  120. In essence, the Lwd functions just hide a reducer value.
  121. *)
  122. type ('a, 'b) reducer
  123. (* A new reducer that transforms sequences with the given [map] and [reduce]
  124. functions. The reducer starts from the [empty] sequence. *)
  125. val make : map:('a -> 'b) -> reduce:('b -> 'b -> 'b) -> ('a, 'b) reducer
  126. (* Updates the [reducer] to transform another sequence.
  127. Intermediate nodes are reused when possible.
  128. Only the "reuse plan" is computed by [update], actual transformation is
  129. done by the [reduce] function.
  130. *)
  131. val update : ('a, 'b) reducer -> 'a seq -> ('a, 'b) reducer
  132. (* Returns the reduced ['b] value if the sequence is non-empty or [None] if
  133. the sequence is empty.
  134. Because transformation is done lazily, [reduce] is the only function
  135. that can call [map] and [reduce].
  136. *)
  137. val reduce : ('a, 'b) reducer -> 'b option
  138. (* Sometimes it is important to track the elements that disappeared from a
  139. sequence. The ['b dropped] type represent all the intermediate result that
  140. were referenced by a reducer and are no longer after an update.
  141. *)
  142. type 'b dropped
  143. val update_and_get_dropped :
  144. ('a, 'b) reducer -> 'a seq -> 'b dropped * ('a, 'b) reducer
  145. val fold_dropped :
  146. [<`All|`Map|`Reduce] -> ('a -> 'b -> 'b) -> 'a dropped -> 'b -> 'b
  147. end