

@ 1,12 +1,43 @@ 



(* Sequence construction *) 



(* Sequence construction 







[Lwd_seq] implements a type of ordered collections with a pure interface. 



In addition, changes to collections are easy to track. 







A collection can be transformed with the usual map, filter and fold 



combinators. If later, the transformation is applied again to an updated 



collection, shared elements (in the sense of physical sharing), the 



result of the previous transformation will be reused for these elements. 







The bookkeeping overhead is O(n) in the number of changes, so O(1) per 



element. 



*) 







type +'a t 



type +'a seq = 'a t 







(* A sequence with no element. *) 



val empty : 'a seq 







(* A singleton sequence. The physical identity of the element is considered 



when reusing previous computations. 







If you do: 



let x1 = element x 



let x2 = element x 







Then x1 and x2 are seen as different elements and no sharing will be done 



during transformation. 



*) 



val element : 'a > 'a seq 







(* Concatenate two sequences into a bigger one. 



As for [element], the physical identity of a sequence is considered for 



reuse. 



*) 



val concat : 'a seq > 'a seq > 'a seq 







(* Look at the contents of a sequence *) 







type ('a, 'b) view = 



 Empty 



 Element of 'a 


@ 15,6 +46,27 @@ type ('a, 'b) view = 



val view : 'a seq > ('a, 'a seq) view 







module Balanced : sig 



(* A variant of the sequence type that guarantees that the depth of 



transformation, as measured in the number of [concat] nodes, grows in 



O(log n) where n is the number of elements in the sequnce. 







This is useful to prevent stack overflows and to avoid degenerate cases 



where a single element change, but it is at the end of a linear sequence 



of [concat] nodes, thus making the total work O(n). 



For instance, in: 







[concat e1 (concat e2 (concat e3 (... (concat e_n))...))] 







If [e_n] changes, the whole spine has to be recomputed. 







Using [Balanced.concat], the representation will be rebalanced 



internally. Then [Balanced.view] should be used to access the balanced 



sequence. 







When working with balanced sequences in a transformation pipeline, it is 



only useful to balance the first sequence of the pipeline. Derived 



sequence will have a depth bounded by the depth of the first one. 



*) 



type 'a t = private 'a seq 



val empty : 'a t 



val element : 'a > 'a t 


@ 23,26 +75,72 @@ module Balanced : sig 



val view : 'a t > ('a, 'a t) view 



end 







(* Lwd interface *) 



(* Lwd interface. 







All sequences live in [Lwd] monad: if a sequence changes slightly, parts 



that have not changed will not be retransformed. 



*) 







(* [fold ~map ~reduce] transforms a sequence. 



If the sequence is nonempty, the [map] function is applied to element nodes 



and the [reduce] function is used to combine transformed concatenated nodes. 



If the sequence is empty, None is returned. 



*) 



val fold : 



map:('a > 'b) > reduce:('b > 'b > 'b) > 'a seq Lwd.t > 'b option Lwd.t 







val fold : map:('a > 'b) > reduce:('b > 'b > 'b) > 'a seq Lwd.t > 'b option Lwd.t 



val fold_monoid : ('a > 'b) > 'b Lwd_utils.monoid > 'a seq Lwd.t > 'b Lwd.t 



val map : ('a > 'b) > 'a seq Lwd.t > 'b seq Lwd.t 



val filter : ('a > bool) > 'a seq Lwd.t > 'a seq Lwd.t 



val filter_map : ('a > 'b option) > 'a seq Lwd.t > 'b seq Lwd.t 



val fold_monoid : 



('a > 'b) > 'b Lwd_utils.monoid > 'a seq Lwd.t > 'b Lwd.t 







(* [map f] transforms a sequence by applying [f] to each element. *) 



val map : 



('a > 'b) > 'a seq Lwd.t > 'b seq Lwd.t 







val filter : 



('a > bool) > 'a seq Lwd.t > 'a seq Lwd.t 







val filter_map : 



('a > 'b option) > 'a seq Lwd.t > 'b seq Lwd.t 







val lift : 'a Lwd.t seq Lwd.t > 'a seq Lwd.t 







(* Lowlevel interface *) 







module Reducer : sig 



(* The interface allows to implement incremental sequence transformation 



outside of the [Lwd] monad. 



Actually, the Lwd functions above are implemented on top of this 



interface. 



*) 







(* A [('a, 'b) reducer] value stores the state necessary to incrementally 



transform an ['a seq] to ['b]. 



In essence, the Lwd functions just hide a reducer value. 



*) 



type ('a, 'b) reducer 







(* A new reducer that transforms sequences with the given [map] and [reduce] 



functions. The reducer starts from the [empty] sequence. *) 



val make : map:('a > 'b) > reduce:('b > 'b > 'b) > ('a, 'b) reducer 







(* Updates the [reducer] to transform another sequence. 



Intermediate nodes are reused when possible. 



Only the "reuse plan" is computed by [update], actual transformation is 



done by the [reduce] function. 



*) 



val update : ('a, 'b) reducer > 'a seq > ('a, 'b) reducer 







(* Returns the reduced ['b] value if the sequence is nonempty or [None] if 



the sequence is empty. 



Because transformation is done lazily, [reduce] is the only function 



that can call [map] and [reduce]. 



*) 



val reduce : ('a, 'b) reducer > 'b option 







(* Sometimes it is important to track the elements that disappeared from a 



sequence. The ['b dropped] type represent all the intermediate result that 



were referenced by a reducer and are no longer after an update. 



*) 



type 'b dropped 



val update_and_get_dropped : 



('a, 'b) reducer > 'a seq > 'b dropped * ('a, 'b) reducer 


