updated version of Sequence

This commit is contained in:
Simon Cruanes 2013-08-28 15:03:05 +02:00
parent 2c3af875b9
commit 37be810bbf
3 changed files with 82 additions and 21 deletions

View file

@ -23,7 +23,7 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*) *)
(** {1 Transient iterators, that abstract on a finite sequence of elements. *) (** {1 Transient iterators, that abstract on a finite sequence of elements.} *)
(** Sequence abstract iterator type *) (** Sequence abstract iterator type *)
type 'a t = ('a -> unit) -> unit type 'a t = ('a -> unit) -> unit
@ -36,6 +36,16 @@ type (+'a, +'b) t2 = ('a -> 'b -> unit) -> unit
(** Build a sequence from a iter function *) (** Build a sequence from a iter function *)
let from_iter f = f let from_iter f = f
(** Call the function repeatedly until it returns None. This
sequence is transient, use {!persistent} if needed! *)
let from_fun f =
fun k ->
let rec next () =
match f () with
| None -> ()
| Some x -> (k x; next ())
in next ()
let empty = fun k -> () let empty = fun k -> ()
let singleton x = fun k -> k x let singleton x = fun k -> k x
@ -111,16 +121,26 @@ let concat s =
let k_seq seq = iter k seq in let k_seq seq = iter k seq in
s k_seq) s k_seq)
let flatten s = concat s
(** Monadic bind. It applies the function to every element of the (** Monadic bind. It applies the function to every element of the
initial sequence, and calls [concat]. *) initial sequence, and calls [concat]. *)
let flatMap f seq = let flatMap f seq =
from_iter from_iter
(fun k -> seq (fun x -> (f x) k)) (fun k -> seq (fun x -> (f x) k))
(** Insert the second element between every element of the sequence *) let fmap f seq =
let intersperse seq elem =
from_iter from_iter
(fun k -> seq (fun x -> k x; k elem)) (fun k ->
seq (fun x -> match f x with
| None -> ()
| Some y -> k y))
(** Insert the given element between every element of the sequence *)
let intersperse elem seq =
fun k ->
let first = ref true in
seq (fun x -> (if !first then first := false else k elem); k x)
(** Mutable unrolled list to serve as intermediate storage *) (** Mutable unrolled list to serve as intermediate storage *)
module MList = struct module MList = struct
@ -173,7 +193,9 @@ module MList = struct
let rec push x l = let rec push x l =
if l.len = Array.length l.content if l.len = Array.length l.content
then begin (* insert in the next block *) then begin (* insert in the next block *)
(if l.tl == _empty () then l.tl <- make (Array.length l.content)); (if l.tl == _empty () then
let n = Array.length l.content in
l.tl <- make (n + n lsr 1));
push x l.tl push x l.tl
end else begin (* insert in l *) end else begin (* insert in l *)
l.content.(l.len) <- x; l.content.(l.len) <- x;
@ -263,6 +285,18 @@ let product outer inner =
outer (fun x -> outer (fun x ->
inner (fun y -> k (x,y)))) inner (fun y -> k (x,y))))
(** [join ~join_row a b] combines every element of [a] with every
element of [b] using [join_row]. If [join_row] returns None, then
the two elements do not combine. Assume that [b] allows for multiple
iterations. *)
let join ~join_row s1 s2 =
fun k ->
s1 (fun a ->
s2 (fun b ->
match join_row a b with
| None -> ()
| Some c -> k c)) (* yield the combination of [a] and [b] *)
(** [unfoldr f b] will apply [f] to [b]. If it (** [unfoldr f b] will apply [f] to [b]. If it
yields [Some (x,b')] then [x] is returned yields [Some (x,b')] then [x] is returned
and unfoldr recurses with [b']. *) and unfoldr recurses with [b']. *)

View file

@ -11,21 +11,32 @@ form must reproduce the above copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other materials provided with following disclaimer in the documentation and/or other materials provided with
the distribution. the distribution.
this software is provided by the copyright holders and contributors "as is" and THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
any express or implied warranties, including, but not limited to, the implied ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
warranties of merchantability and fitness for a particular purpose are WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
disclaimed. in no event shall the copyright holder or contributors be liable DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
for any direct, indirect, incidental, special, exemplary, or consequential FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
damages (including, but not limited to, procurement of substitute goods or DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
services; loss of use, data, or profits; or business interruption) however SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
caused and on any theory of liability, whether in contract, strict liability, CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
or tort (including negligence or otherwise) arising in any way out of the use OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
of this software, even if advised of the possibility of such damage. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*) *)
(** Transient iterators, that abstract on a finite sequence of elements. They (** {1 Transient iterators, that abstract on a finite sequence of elements.} *)
are designed to allow easy transfer (mappings) between data structures,
without defining n^2 conversions between the n types. *) (** The iterators are designed to allow easy transfer (mappings) between data
structures, without defining n^2 conversions between the n types. The
implementation relies on the assumption that a sequence can be iterated
on as many times as needed; this choice allows for high performance
of many combinators. However, for transient iterators, the {!persistent}
function is provided, storing elements of a transient iterator
in memory; the iterator can then be used several times.
Note that some combinators also return sequences (e.g. {!group}). The
transformation is computed on the fly every time one iterates over
the resulting sequence. If a transformation performs heavy computation,
{!persistent} can also be used as intermediate storage. *)
type +'a t = ('a -> unit) -> unit type +'a t = ('a -> unit) -> unit
(** Sequence abstract iterator type, representing a finite sequence of (** Sequence abstract iterator type, representing a finite sequence of
@ -41,6 +52,10 @@ type (+'a, +'b) t2 = ('a -> 'b -> unit) -> unit
val from_iter : (('a -> unit) -> unit) -> 'a t val from_iter : (('a -> unit) -> unit) -> 'a t
(** Build a sequence from a iter function *) (** Build a sequence from a iter function *)
val from_fun : (unit -> 'a option) -> 'a t
(** Call the function repeatedly until it returns None. This
sequence is transient, use {!persistent} if needed! *)
val empty : 'a t val empty : 'a t
(** Empty sequence *) (** Empty sequence *)
@ -103,11 +118,17 @@ val append : 'a t -> 'a t -> 'a t
val concat : 'a t t -> 'a t val concat : 'a t t -> 'a t
(** Concatenate a sequence of sequences into one sequence *) (** Concatenate a sequence of sequences into one sequence *)
val flatten : 'a t t -> 'a t
(** Alias for {!concat} *)
val flatMap : ('a -> 'b t) -> 'a t -> 'b t val flatMap : ('a -> 'b t) -> 'a t -> 'b t
(** Monadic bind. It applies the function to every element of the (** Monadic bind. It applies the function to every element of the
initial sequence, and calls [concat]. *) initial sequence, and calls [concat]. *)
val intersperse : 'a t -> 'a -> 'a t val fmap : ('a -> 'b option) -> 'a t -> 'b t
(** Specialized version of {!flatMap} for options. *)
val intersperse : 'a -> 'a t -> 'a t
(** Insert the second element between every element of the sequence *) (** Insert the second element between every element of the sequence *)
val persistent : 'a t -> 'a t val persistent : 'a t -> 'a t
@ -132,6 +153,12 @@ val product : 'a t -> 'b t -> ('a * 'b) t
by calling [persistent] on it, so that it can be traversed by calling [persistent] on it, so that it can be traversed
several times (outer loop of the product) *) several times (outer loop of the product) *)
val join : join_row:('a -> 'b -> 'c option) -> 'a t -> 'b t -> 'c t
(** [join ~join_row a b] combines every element of [a] with every
element of [b] using [join_row]. If [join_row] returns None, then
the two elements do not combine. Assume that [b] allows for multiple
iterations. *)
val unfoldr : ('b -> ('a * 'b) option) -> 'b -> 'a t val unfoldr : ('b -> ('a * 'b) option) -> 'b -> 'a t
(** [unfoldr f b] will apply [f] to [b]. If it (** [unfoldr f b] will apply [f] to [b]. If it
yields [Some (x,b')] then [x] is returned yields [Some (x,b')] then [x] is returned

View file

@ -35,7 +35,7 @@ type 'a t
val empty : cmp:('a -> 'a -> int) -> 'a t val empty : cmp:('a -> 'a -> int) -> 'a t
(** Create an empty set *) (** Create an empty set *)
val is_empty : 'a t -> bool val is_empty : _ t -> bool
(** Is the set empty? *) (** Is the set empty? *)
val mem : 'a t -> 'a -> bool val mem : 'a t -> 'a -> bool