From d58a50ed59a383abab2ba51e35d6afc915fe9182 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Sat, 25 Jul 2015 00:55:46 +0200 Subject: [PATCH] breaking: big refactoring of `CCLinq` (now simpler and cleaner) --- src/advanced/CCLinq.ml | 670 ++++++++++++++++------------------------ src/advanced/CCLinq.mli | 340 ++++++++++---------- 2 files changed, 431 insertions(+), 579 deletions(-) diff --git a/src/advanced/CCLinq.ml b/src/advanced/CCLinq.ml index 7da7ccda..712f25b7 100644 --- a/src/advanced/CCLinq.ml +++ b/src/advanced/CCLinq.ml @@ -32,20 +32,12 @@ type 'a ord = 'a -> 'a -> int type 'a hash = 'a -> int type 'a with_err = [`Ok of 'a | `Error of string ] -(* TODO: add CCVector as a collection *) - let _id x = x exception ExitWithError of string let _exit_with_error s = raise (ExitWithError s) let _error_of_exn f = try `Ok (f ()) with ExitWithError s -> `Error s -type 'a collection = - | Seq : 'a sequence -> 'a collection - | List : 'a list -> 'a collection - | Set : (module Sequence.Set.S - with type elt = 'a and type t = 'b) * 'b -> 'a collection - module PMap = struct type ('a, 'b) t = { is_empty : unit -> bool; @@ -62,9 +54,6 @@ module PMap = struct let to_seq m = m.to_seq let fold f acc m = m.fold f acc let size m = m.size () - let get_err m x = match m.get x with - | Some y -> `Ok y - | None -> `Error "PMap.get: lookup error" type ('a, 'b) build = { mutable cur : ('a, 'b) t; @@ -139,6 +128,21 @@ module PMap = struct | FromCmp cmp -> make_cmp ~cmp () | FromHash (eq,hash) -> make_hash ~eq ~hash () + (* choose a build method from the optional arguments *) + let _make_build ?cmp ?eq ?hash () = + let _maybe default o = match o with + | Some x -> x + | None -> default + in + match eq, hash with + | Some _, _ + | _, Some _ -> + FromHash ( _maybe (=) eq, _maybe Hashtbl.hash hash) + | _ -> + match cmp with + | Some f -> FromCmp f + | _ -> Default + let multimap_of_seq ?(build=make ()) seq = seq (fun (k,v) -> build.update k (function @@ -154,11 +158,6 @@ module PMap = struct | Some n -> Some (n+1))); build.cur - let get_exn m x = - match m.get x with - | None -> raise Not_found - | Some x -> x - (* map values *) let map f m = { is_empty = m.is_empty; @@ -175,14 +174,12 @@ module PMap = struct let to_list m = Sequence.to_rev_list m.to_seq - let to_coll m = Seq m.to_seq - - let reverse ~build m = + let reverse_ ~build m = let build = make ~build () in let seq = Sequence.map (fun (x,y) -> y,x) (to_seq m) in multimap_of_seq ~build seq - let reverse_multimap ~build m = + let reverse_multimap_ ~build m = let build = make ~build () in let seq = to_seq m in let seq = Sequence.flat_map @@ -190,6 +187,37 @@ module PMap = struct ) seq in multimap_of_seq ~build seq + + let reverse ?cmp ?eq ?hash () m = + let build = _make_build ?cmp ?eq ?hash () in + reverse_ ~build m + + let reverse_multimap ?cmp ?eq ?hash () m = + let build = _make_build ?cmp ?eq ?hash () in + reverse_multimap_ ~build m + + let fold_multimap f acc m = + m.fold (fun acc x l -> List.fold_left (fun acc y -> f acc x y) acc l) acc + + let get_seq key m = match get m key with + | None -> Sequence.empty + | Some x -> Sequence.return x + + let iter m = m.to_seq + + let flatten m = + let seq = Sequence.flat_map + (fun (k,v) -> Sequence.map (fun v' -> k,v') v) + m.to_seq + in + seq + + let flatten_l m = + let seq = Sequence.flatMap + (fun (k,v) -> Sequence.map (fun v' -> k,v') (Sequence.of_list v)) + m.to_seq + in + seq end type 'a search_result = @@ -209,109 +237,15 @@ type ('a,'b) group_join_descr = { } module Coll = struct - let of_seq s = Seq s - let of_list l = List l - let of_array a = Seq (Sequence.of_array a) - - let set_of_seq (type elt) ?(cmp=Pervasives.compare) seq = - let module S = Sequence.Set.Make(struct - type t = elt - let compare = cmp - end) in - let set = S.of_seq seq in - Set ((module S), set) - - let to_seq (type elt) = function - | Seq s -> s - | List l -> (fun k -> List.iter k l) - | Set (m, set) -> - let module S = (val m : Sequence.Set.S - with type elt = elt and type t = 'b) in - S.to_seq set - - let to_list (type elt) = function - | Seq s -> Sequence.to_list s - | List l -> l - | Set (m, set) -> - let module S = (val m : Sequence.Set.S - with type elt = elt and type t = 'b) in - S.elements set - - let _fmap ~lst ~seq c = match c with - | List l -> List (lst l) - | Seq s -> Seq (seq s) - | Set _ -> - List (lst (to_list c)) - - let fold (type elt) f acc c = match c with - | List l -> List.fold_left f acc l - | Seq s -> Sequence.fold f acc s - | Set (m, set) -> - let module S = (val m : Sequence.Set.S - with type elt = elt and type t = 'b) in - S.fold (fun x acc -> f acc x) set acc - - let map f c = - _fmap ~lst:(List.map f) ~seq:(Sequence.map f) c - - let filter p c = - _fmap ~lst:(List.filter p) ~seq:(Sequence.filter p) c - - let flat_map f c = - let c' = to_seq c in - Seq (Sequence.flatMap (fun x -> to_seq (f x)) c') - - let filter_map f c = - _fmap ~lst:(CCList.filter_map f) ~seq:(Sequence.fmap f) c - - let size (type elt) = function - | List l -> List.length l - | Seq s -> Sequence.length s - | Set (m, set) -> - let module S = (val m : Sequence.Set.S - with type elt = elt and type t = 'b) in - S.cardinal set - - let choose_exn (type elt) c = - let fail () = _exit_with_error "choose: empty collection" in - match c with - | List [] -> fail () - | List (x::_) -> x - | Seq s -> - begin match Sequence.to_list (Sequence.take 1 s) with - | [x] -> x - | _ -> fail () - end - | Set (m, set) -> - let module S = (val m : Sequence.Set.S - with type elt = elt and type t = 'b) in - try S.choose set with Not_found -> fail () - - let choose_err c = - try `Ok (choose_exn c) - with ExitWithError s -> `Error s - - let take n c = - _fmap ~lst:(CCList.take n) ~seq:(Sequence.take n) c + let choose s = Sequence.take 1 s exception MySurpriseExit - let _seq_take_while p seq k = - try - seq (fun x -> if not (p x) then k x else raise MySurpriseExit) - with MySurpriseExit -> () + let distinct (type k) ~cmp s = + let module S = Sequence.Set.Make(struct type t = k let compare = cmp end) in + S.to_seq (S.of_seq s) - let take_while p c = - of_seq (_seq_take_while p (to_seq c)) - - let distinct ~cmp c = set_of_seq ~cmp (to_seq c) - - let sort cmp c = match c with - | List l -> List (List.sort cmp l) - | Seq s -> List (List.sort cmp (Sequence.to_rev_list s)) - | _ -> set_of_seq ~cmp (to_seq c) - - let search obj c = + let search obj s = let _search_seq obj seq = let ret = ref None in begin try @@ -324,21 +258,11 @@ module Coll = struct | None -> obj#failure | Some x -> x in - _search_seq obj (to_seq c) - - let contains (type elt) ~eq x c = match c with - | List l -> List.exists (eq x) l - | Seq s -> Sequence.exists (eq x) s - | Set (m, set) -> - let module S = (val m : Sequence.Set.S - with type elt = elt and type t = 'b) in - (* XXX: here we don't use the equality relation *) - S.mem x set + _search_seq obj s let do_join ~join c1 c2 = let build1 = - let seq = to_seq c1 in - let seq = Sequence.map (fun x -> join.join_key1 x, x) seq in + let seq = Sequence.map (fun x -> join.join_key1 x, x) c1 in PMap.multimap_of_seq ~build:(PMap.make ~build:join.join_build ()) seq in let l = Sequence.fold @@ -352,14 +276,14 @@ module Coll = struct | None -> acc | Some res -> res::acc ) acc l1 - ) [] (to_seq c2) + ) [] c2 in - of_list l + Sequence.of_list l let do_group_join ~gjoin c1 c2 = let build = PMap.make ~build:gjoin.gjoin_build () in - to_seq c1 (fun x -> PMap.add build x []); - to_seq c2 + c1 (fun x -> PMap.add build x []); + c2 (fun y -> (* project [y] into some element of [c1] *) let x = gjoin.gjoin_proj y in @@ -371,16 +295,12 @@ module Coll = struct ); PMap.build_get build - let do_product c1 c2 = - let s1 = to_seq c1 and s2 = to_seq c2 in - of_seq (Sequence.product s1 s2) - let do_union ~build c1 c2 = let build = PMap.make ~build () in - to_seq c1 (fun x -> PMap.add build x ()); - to_seq c2 (fun x -> PMap.add build x ()); + c1 (fun x -> PMap.add build x ()); + c2 (fun x -> PMap.add build x ()); let seq = PMap.to_seq (PMap.build_get build) in - of_seq (Sequence.map fst seq) + Sequence.map fst seq type inter_status = | InterLeft @@ -389,8 +309,8 @@ module Coll = struct let do_inter ~build c1 c2 = let build = PMap.make ~build () in let l = ref [] in - to_seq c1 (fun x -> PMap.add build x InterLeft); - to_seq c2 (fun x -> + c1 (fun x -> PMap.add build x InterLeft); + c2 (fun x -> PMap.update build x (function | None -> Some InterDone @@ -400,49 +320,40 @@ module Coll = struct Some InterDone ) ); - of_list !l + Sequence.of_list !l let do_diff ~build c1 c2 = let build = PMap.make ~build () in - to_seq c2 (fun x -> PMap.add build x ()); + c2 (fun x -> PMap.add build x ()); let map = PMap.build_get build in (* output elements of [c1] not in [map] *) - let seq = to_seq c1 in - of_seq (Sequence.filter (fun x -> not (PMap.mem map x)) seq) + Sequence.filter (fun x -> not (PMap.mem map x)) c1 end (** {2 Query operators} *) -type (_,_) safety = - | Explicit : ('a, 'a with_err) safety - | Implicit : ('a, 'a) safety - type (_, _) unary = - | PMap : ('a -> 'b) -> ('a collection, 'b collection) unary - | GeneralMap : ('a -> 'b) -> ('a, 'b) unary - | Filter : ('a -> bool) -> ('a collection, 'a collection) unary - | Fold : ('b -> 'a -> 'b) * 'b -> ('a collection, 'b) unary - | FoldMap : ('acc -> 'a -> 'b -> 'acc) * 'acc - -> (('a,'b) PMap.t, 'acc) unary - | Reduce : ('c, 'd) safety * ('a -> 'b) * ('a -> 'b -> 'b) * ('b -> 'c) - -> ('a collection, 'd) unary - | Size : ('a collection, int) unary - | Choose : ('a,'b) safety -> ('a collection, 'b) unary - | FilterMap : ('a -> 'b option) -> ('a collection, 'b collection) unary - | FlatMap : ('a -> 'b collection) -> ('a collection, 'b collection) unary - | Take : int -> ('a collection, 'a collection) unary - | TakeWhile : ('a -> bool) -> ('a collection, 'a collection) unary - | Sort : 'a ord -> ('a collection, 'a collection) unary - | Distinct : 'a ord -> ('a collection, 'a collection) unary + | Map : ('a -> 'b) -> ('a, 'b ) unary + | Filter : ('a -> bool) -> ('a, 'a ) unary + | Fold : ('b -> 'a -> 'b) * 'b -> ('a, 'b) unary + | Reduce : ('a -> 'b) * ('a -> 'b -> 'b) * ('b -> 'c) + -> ('a, 'c) unary + | Size : ('a, int) unary + | Choose : ('a, 'a) unary + | FilterMap : ('a -> 'b option) -> ('a, 'b) unary + | FlatMap : ('a -> 'b sequence) -> ('a, 'b) unary + | Take : int -> ('a, 'a) unary + | TakeWhile : ('a -> bool) -> ('a, 'a) unary + | Sort : 'a ord -> ('a, 'a) unary + | Distinct : 'a ord -> ('a, 'a) unary | Search : < check: ('a -> 'b search_result); failure : 'b; - > -> ('a collection, 'b) unary - | Contains : 'a equal * 'a -> ('a collection, bool) unary - | Get : ('b,'c) safety * 'a -> (('a,'b) PMap.t, 'c) unary + > -> ('a, 'b) unary + | Contains : 'a equal * 'a -> ('a, bool) unary | GroupBy : 'b PMap.build_method * ('a -> 'b) - -> ('a collection, ('b,'a list) PMap.t) unary - | Count : 'a PMap.build_method -> ('a collection, ('a, int) PMap.t) unary + -> ('a, ('b,'a list) PMap.t) unary + | Count : 'a PMap.build_method -> ('a, ('a, int) PMap.t) unary | Lazy : ('a lazy_t, 'a) unary type set_op = @@ -451,90 +362,95 @@ type set_op = | Diff type (_, _, _) binary = + | App : ('a -> 'b, 'a, 'b) binary | Join : ('a, 'b, 'key, 'c) join_descr - -> ('a collection, 'b collection, 'c collection) binary + -> ('a, 'b, 'c) binary | GroupJoin : ('a, 'b) group_join_descr - -> ('a collection, 'b collection, ('a, 'b list) PMap.t) binary - | Product : ('a collection, 'b collection, ('a*'b) collection) binary - | Append : ('a collection, 'a collection, 'a collection) binary + -> ('a, 'b, ('a, 'b list) PMap.t) binary + | Product : ('a, 'b, ('a*'b)) binary + | Append : ('a, 'a, 'a) binary | SetOp : set_op * 'a PMap.build_method - -> ('a collection, 'a collection, 'a collection) binary + -> ('a, 'a, 'a) binary (* type of queries that return a 'a *) and 'a t = - | Start : 'a -> 'a t - | Catch : 'a with_err t -> 'a t + | Return : 'a -> 'a t + | OfSeq : 'a sequence -> 'a t | Unary : ('a, 'b) unary * 'a t -> 'b t | Binary : ('a, 'b, 'c) binary * 'a t * 'b t -> 'c t - | QueryMap : ('a -> 'b) * 'a t -> 'b t | Bind : ('a -> 'b t) * 'a t -> 'b t + | Reflect : 'a t -> 'a sequence t -let start x = Start x +let start x = Return x let of_list l = - Start (Coll.of_list l) + OfSeq (Sequence.of_list l) let of_array a = - Start (Coll.of_array a) + OfSeq (Sequence.of_array a) let of_array_i a = - Start (Coll.of_seq (Sequence.of_array_i a)) + OfSeq (Sequence.of_array_i a) let of_hashtbl h = - Start (Coll.of_seq (Sequence.of_hashtbl h)) + OfSeq (Sequence.of_hashtbl h) + +let range i j = OfSeq (Sequence.int_range ~start:i ~stop:j) + +let (--) = range let of_seq seq = - Start (Coll.of_seq seq) + OfSeq seq let of_queue q = - Start (Coll.of_seq (Sequence.of_queue q)) + OfSeq (Sequence.of_queue q) let of_stack s = - Start (Coll.of_seq (Sequence.of_stack s)) + OfSeq (Sequence.of_stack s) let of_string s = - Start (Coll.of_seq (Sequence.of_str s)) + OfSeq (Sequence.of_str s) (** {6 Execution} *) let rec _optimize : type a. a t -> a t = fun q -> match q with - | Start _ -> q - | Catch q' -> Catch (_optimize q') + | Return _ -> q | Unary (u, q) -> _optimize_unary u (_optimize q) | Binary (b, q1, q2) -> _optimize_binary b (_optimize q1) (_optimize q2) - | QueryMap (f, q) -> QueryMap (f, _optimize q) + | Reflect _ -> q + | OfSeq _ -> q | Bind _ -> q (* cannot optimize before execution *) and _optimize_unary : type a b. (a,b) unary -> a t -> b t = fun u q -> match u, q with - | PMap f, Unary (PMap g, q') -> - _optimize_unary (PMap (fun x -> f (g x))) q' - | Filter p, Unary (PMap f, cont) -> + | Map f, Unary (Map g, q') -> + _optimize_unary (Map (fun x -> f (g x))) q' + | Filter p, Unary (Map f, cont) -> _optimize_unary (FilterMap (fun x -> let y = f x in if p y then Some y else None)) cont - | PMap f, Unary (Filter p, cont) -> + | Map f, Unary (Filter p, cont) -> _optimize_unary (FilterMap (fun x -> if p x then Some (f x) else None)) cont - | PMap _, Binary (Append, q1, q2) -> + | Map _, Binary (Append, q1, q2) -> _optimize_binary Append (Unary (u, q1)) (Unary (u, q2)) | Filter _, Binary (Append, q1, q2) -> _optimize_binary Append (Unary (u, q1)) (Unary (u, q2)) - | Fold (f,acc), Unary (PMap f', cont) -> + | Fold (f,acc), Unary (Map f', cont) -> _optimize_unary (Fold ((fun acc x -> f acc (f' x)), acc)) cont - | Reduce (safety, start, mix, stop), Unary (PMap f, cont) -> + | Reduce (start, mix, stop), Unary (Map f, cont) -> _optimize_unary - (Reduce (safety, + (Reduce ( (fun x -> start (f x)), (fun x acc -> mix (f x) acc), stop)) cont - | Size, Unary (PMap _, cont) -> + | Size, Unary (Map _, cont) -> _optimize_unary Size cont (* ignore the map! *) | Size, Unary (Sort _, cont) -> _optimize_unary Size cont @@ -542,120 +458,119 @@ and _optimize_unary : type a b. (a,b) unary -> a t -> b t (* TODO: other cases *) and _optimize_binary : type a b c. (a,b,c) binary -> a t -> b t -> c t = fun b q1 q2 -> match b, q1, q2 with - | _ -> Binary (b, q1, q2) (* TODO *) + | App, Return f, x -> Unary (Map f, x) + | App, _, _ -> Binary (b, q1, q2) + | Join _, _, _ -> Binary (b, q1, q2) + | GroupJoin _, _, _ -> Binary (b, q1, q2) + | Product, _, _ -> Binary (b, q1, q2) + | Append, _, _ -> Binary (b, q1, q2) + | SetOp _, _, _ -> Binary (b, q1, q2) (* apply a unary operator on a collection *) -let _do_unary : type a b. (a,b) unary -> a -> b +let _do_unary : type a b. (a,b) unary -> a sequence -> b sequence = fun u c -> match u with - | PMap f -> Coll.map f c - | GeneralMap f -> f c - | Filter p -> Coll.filter p c - | Fold (f, acc) -> Coll.fold f acc c - | FoldMap (f, acc) -> PMap.fold f acc c - | Reduce (safety, start, mix, stop) -> + | Map f -> Sequence.map f c + | Filter p -> Sequence.filter p c + | Fold (f, acc) -> Sequence.return (Sequence.fold f acc c) + | Reduce (start, mix, stop) -> let acc = Sequence.fold (fun acc x -> match acc with | None -> Some (start x) | Some acc -> Some (mix x acc) - ) None (Coll.to_seq c) + ) None c in - begin match acc, safety with - | Some x, Implicit -> stop x - | None, Implicit -> _exit_with_error "reduce: empty collection" - | Some x, Explicit -> `Ok (stop x) - | None, Explicit -> `Error "reduce: empty collection" + begin match acc with + | None -> Sequence.empty + | Some x -> Sequence.return (stop x) end - | Size -> Coll.size c - | Choose Implicit -> Coll.choose_exn c - | Choose Explicit -> Coll.choose_err c - | FilterMap f -> Coll.filter_map f c - | FlatMap f -> Coll.flat_map f c - | Take n -> Coll.take n c - | TakeWhile p -> Coll.take_while p c - | Sort cmp -> Coll.sort cmp c + | Size -> Sequence.return (Sequence.length c) + | Choose -> Coll.choose c + | FilterMap f -> Sequence.filter_map f c + | FlatMap f -> Sequence.flat_map f c + | Take n -> Sequence.take n c + | TakeWhile p -> Sequence.take_while p c + | Sort cmp -> Sequence.sort ~cmp c | Distinct cmp -> Coll.distinct ~cmp c - | Search obj -> Coll.search obj c - | Get (Implicit, k) -> PMap.get_exn c k - | Get (Explicit, k) -> PMap.get_err c k + | Search obj -> Sequence.return (Coll.search obj c) | GroupBy (build,f) -> - let seq = Sequence.map (fun x -> f x, x) (Coll.to_seq c) in - PMap.multimap_of_seq ~build:(PMap.make ~build ()) seq - | Contains (eq, x) -> Coll.contains ~eq x c + let seq = Sequence.map (fun x -> f x, x) c in + Sequence.return (PMap.multimap_of_seq ~build:(PMap.make ~build ()) seq) + | Contains (eq, x) -> Sequence.return (Sequence.mem ~eq x c) | Count build -> - PMap.count_of_seq ~build:(PMap.make ~build ()) (Coll.to_seq c) - | Lazy -> Lazy.force c + Sequence.return (PMap.count_of_seq ~build:(PMap.make ~build ()) c) + | Lazy -> Sequence.map Lazy.force c -let _do_binary : type a b c. (a, b, c) binary -> a -> b -> c +let _do_binary : type a b c. (a, b, c) binary -> a sequence -> b sequence -> c sequence = fun b c1 c2 -> match b with | Join join -> Coll.do_join ~join c1 c2 - | GroupJoin gjoin -> Coll.do_group_join ~gjoin c1 c2 - | Product -> Coll.do_product c1 c2 - | Append -> - Coll.of_seq (Sequence.append (Coll.to_seq c1) (Coll.to_seq c2)) + | GroupJoin gjoin -> Sequence.return (Coll.do_group_join ~gjoin c1 c2) + | Product -> Sequence.product c1 c2 + | Append -> Sequence.append c1 c2 + | App -> Sequence.(c1 <*> c2) | SetOp (Inter,build) -> Coll.do_inter ~build c1 c2 | SetOp (Union,build) -> Coll.do_union ~build c1 c2 | SetOp (Diff,build) -> Coll.do_diff ~build c1 c2 -let rec _run : type a. opt:bool -> a t -> a +let rec _run : type a. opt:bool -> a t -> a sequence = fun ~opt q -> match q with - | Start c -> c - | Catch q' -> - begin match _run ~opt q' with - | `Ok x -> x - | `Error s -> _exit_with_error s - end + | Return c -> Sequence.return c | Unary (u, q') -> _do_unary u (_run ~opt q') | Binary (b, q1, q2) -> _do_binary b (_run ~opt q1) (_run ~opt q2) - | QueryMap (f, q') -> f (_run ~opt q') + | OfSeq s -> s | Bind (f, q') -> - let x = _run ~opt q' in - let q'' = f x in - let q'' = if opt then _optimize q'' else q'' in - _run ~opt q'' + let seq = _run ~opt q' in + Sequence.flat_map + (fun x -> + let q'' = f x in + let q'' = if opt then _optimize q'' else q'' in + _run ~opt q'' + ) seq + | Reflect q -> + let seq = Sequence.persistent_lazy (_run ~opt q) in + Sequence.return seq + +let _apply_limit ?limit seq = match limit with + | None -> seq + | Some l -> Sequence.take l seq (* safe execution *) -let run q = - try `Ok (_run ~opt:true (_optimize q)) - with - | ExitWithError s -> `Error s - | e -> `Error (Printexc.to_string e) +let run ?limit q = + let seq = _run ~opt:true (_optimize q) in + _apply_limit ?limit seq -let run_exn q = - match run q with - | `Ok x -> x - | `Error s -> failwith s +let run_no_optim ?limit q = + let seq = _run ~opt:false q in + _apply_limit ?limit seq -let run_no_optim q = - try `Ok (_run ~opt:false q) - with - | ExitWithError s -> `Error s - | e -> `Error (Printexc.to_string e) +let run1 q = + let seq = _run ~opt:true (_optimize q) in + match Sequence.head seq with + | Some x -> x + | None -> raise Not_found -(** {6 Basics on Collections} *) +(** {6 Basics} *) -let map f q = Unary (PMap f, q) +let empty = OfSeq Sequence.empty + +let map f q = Unary (Map f, q) + +let (>|=) q f = Unary (Map f, q) let filter p q = Unary (Filter p, q) -let choose q = Unary (Choose Implicit, q) - -let choose_err q = Unary (Choose Explicit, q) +let choose q = Unary (Choose, q) let filter_map f q = Unary (FilterMap f, q) let flat_map f q = Unary (FlatMap f, q) -let flat_map_seq f q = - let f' x = Coll.of_seq (f x) in - Unary (FlatMap f', q) - let flat_map_l f q = - let f' x = Coll.of_list (f x) in + let f' x = Sequence.of_list (f x) in Unary (FlatMap f', q) -let flatten q = Unary (FlatMap (fun x->x), q) +let flatten_seq q = Unary (FlatMap (fun x->x), q) -let flatten_l q = Unary (FlatMap Coll.of_list, q) +let flatten q = Unary (FlatMap Sequence.of_list, q) let take n q = Unary (Take n, q) @@ -666,86 +581,17 @@ let sort ?(cmp=Pervasives.compare) () q = Unary (Sort cmp, q) let distinct ?(cmp=Pervasives.compare) () q = Unary (Distinct cmp, q) -(* choose a build method from the optional arguments *) -let _make_build ?cmp ?eq ?hash () = - let _maybe default o = match o with - | Some x -> x - | None -> default - in - match eq, hash with - | Some _, _ - | _, Some _ -> - PMap.FromHash ( _maybe (=) eq, _maybe Hashtbl.hash hash) - | _ -> - match cmp with - | Some f -> PMap.FromCmp f - | _ -> PMap.Default - -(** {6 Queries on PMaps} *) - -module M = struct - let get key q = - Unary (Get (Implicit, key), q) - - let get_err key q = - Unary (Get (Explicit, key), q) - - let iter q = - Unary (GeneralMap (fun m -> Coll.of_seq m.PMap.to_seq), q) - - let flatten q = - let f m = - let seq = Sequence.flat_map - (fun (k,v) -> Sequence.map (fun v' -> k,v') (Coll.to_seq v)) - m.PMap.to_seq - in Coll.of_seq seq - in - Unary (GeneralMap f, q) - - let flatten' q = - let f m = - let seq = Sequence.flatMap - (fun (k,v) -> Sequence.map (fun v' -> k,v') (Sequence.of_list v)) - m.PMap.to_seq - in Coll.of_seq seq - in - Unary (GeneralMap f, q) - - let map f q = - Unary (GeneralMap (PMap.map f), q) - - let to_list q = - Unary (GeneralMap PMap.to_list, q) - - let reverse ?cmp ?eq ?hash () q = - let build = _make_build ?cmp ?eq ?hash () in - Unary (GeneralMap (PMap.reverse ~build), q) - - let reverse_multimap ?cmp ?eq ?hash () q = - let build = _make_build ?cmp ?eq ?hash () in - Unary (GeneralMap (PMap.reverse_multimap ~build), q) - - let fold f acc q = - Unary (FoldMap (f, acc), q) - - let fold_multimap f acc q = - let f' acc x l = - List.fold_left (fun acc y -> f acc x y) acc l - in - Unary (FoldMap (f', acc), q) -end - let group_by ?cmp ?eq ?hash f q = - Unary (GroupBy (_make_build ?cmp ?eq ?hash (),f), q) + Unary (GroupBy (PMap._make_build ?cmp ?eq ?hash (),f), q) let group_by' ?cmp ?eq ?hash f q = - M.iter (group_by ?cmp ?eq ?hash f q) + flat_map PMap.iter (group_by ?cmp ?eq ?hash f q) let count ?cmp ?eq ?hash () q = - Unary (Count (_make_build ?cmp ?eq ?hash ()), q) + Unary (Count (PMap._make_build ?cmp ?eq ?hash ()), q) let count' ?cmp () q = - M.iter (count ?cmp () q) + flat_map PMap.iter (count ?cmp () q) let fold f acc q = Unary (Fold (f, acc), q) @@ -755,10 +601,7 @@ let size q = Unary (Size, q) let sum q = Unary (Fold ((+), 0), q) let reduce start mix stop q = - Unary (Reduce (Implicit, start,mix,stop), q) - -let reduce_err start mix stop q = - Unary (Reduce (Explicit, start,mix,stop), q) + Unary (Reduce (start,mix,stop), q) let _avg_start x = (x,1) let _avg_mix x (y,n) = (x+y,n+1) @@ -768,13 +611,9 @@ let _lift_some f x y = match y with | None -> Some x | Some y -> Some (f x y) -let max q = Unary (Reduce (Implicit, _id, Pervasives.max, _id), q) -let min q = Unary (Reduce (Implicit, _id, Pervasives.min, _id), q) -let average q = Unary (Reduce (Implicit, _avg_start, _avg_mix, _avg_stop), q) - -let max_err q = Unary (Reduce (Explicit, _id, Pervasives.max, _id), q) -let min_err q = Unary (Reduce (Explicit, _id, Pervasives.min, _id), q) -let average_err q = Unary (Reduce (Explicit, _avg_start, _avg_mix, _avg_stop), q) +let max q = Unary (Reduce (_id, Pervasives.max, _id), q) +let min q = Unary (Reduce (_id, Pervasives.min, _id), q) +let average q = Unary (Reduce (_avg_start, _avg_mix, _avg_stop), q) let is_empty q = Unary (Search (object @@ -814,7 +653,7 @@ let find_map f q = (** {6 Binary Operators} *) let join ?cmp ?eq ?hash join_key1 join_key2 ~merge q1 q2 = - let join_build = _make_build ?eq ?hash ?cmp () in + let join_build = PMap._make_build ?eq ?hash ?cmp () in let j = { join_key1; join_key2; @@ -824,7 +663,7 @@ let join ?cmp ?eq ?hash join_key1 join_key2 ~merge q1 q2 = Binary (Join j, q1, q2) let group_join ?cmp ?eq ?hash gjoin_proj q1 q2 = - let gjoin_build = _make_build ?eq ?hash ?cmp () in + let gjoin_build = PMap._make_build ?eq ?hash ?cmp () in let j = { gjoin_proj; gjoin_build; @@ -836,15 +675,15 @@ let product q1 q2 = Binary (Product, q1, q2) let append q1 q2 = Binary (Append, q1, q2) let inter ?cmp ?eq ?hash () q1 q2 = - let build = _make_build ?cmp ?eq ?hash () in + let build = PMap._make_build ?cmp ?eq ?hash () in Binary (SetOp (Inter, build), q1, q2) let union ?cmp ?eq ?hash () q1 q2 = - let build = _make_build ?cmp ?eq ?hash () in + let build = PMap._make_build ?cmp ?eq ?hash () in Binary (SetOp (Union, build), q1, q2) let diff ?cmp ?eq ?hash () q1 q2 = - let build = _make_build ?cmp ?eq ?hash () in + let build = PMap._make_build ?cmp ?eq ?hash () in Binary (SetOp (Diff, build), q1, q2) let fst q = map fst q @@ -856,71 +695,86 @@ let map2 f q = map (fun (x,y) -> x, f y) q let flatten_opt q = filter_map _id q let opt_unwrap q = - QueryMap ((function - | Some x -> x - | None -> _exit_with_error "opt_unwrap"), q) + Unary + (Map + (function + | Some x -> x + | None -> _exit_with_error "opt_unwrap"), + q + ) -let catch q = - QueryMap ((function - | `Ok x -> x - | `Error s -> _exit_with_error s), q) +(** {6 Applicative} *) + +let pure x = Return x + +let app f x = Binary (App, f, x) + +let (<*>) = app (** {6 Monadic stuff} *) -let return x = Start x +let return x = Return x let bind f q = Bind (f,q) let (>>=) x f = Bind (f, x) -let query_map f q = QueryMap (f, q) - (** {6 Misc} *) let lazy_ q = Unary (Lazy, q) +let reflect q = Reflect q + +(** {6 Infix} *) + +module Infix = struct + let (>>=) = (>>=) + let (>|=) = (>|=) + let (<*>) = (<*>) + let (--) = (--) +end + (** {6 Adapters} *) -let to_array q = - QueryMap ((fun c -> Array.of_list (Coll.to_list c)), q) - let to_seq q = - QueryMap ((fun c -> Sequence.persistent (Coll.to_seq c)), q) + Unary (Map Sequence.persistent, Reflect q) let to_hashtbl q = - QueryMap ((fun c -> Sequence.to_hashtbl (Coll.to_seq c)), q) + Unary (Map (fun c -> Sequence.to_hashtbl c), Reflect q) let to_queue q = - QueryMap ((fun c q -> Sequence.to_queue q (Coll.to_seq c)), q) + Unary (Map (fun c -> let q = Queue.create() in Sequence.to_queue q c; q), Reflect q) let to_stack q = - QueryMap ((fun c s -> Sequence.to_stack s (Coll.to_seq c)), q) + Unary (Map (fun c -> let s = Stack.create () in Sequence.to_stack s c; s), Reflect q) -module L = struct - let of_list l = Start (Coll.of_list l) - let to_list q = - QueryMap (Coll.to_list, q) - let run q = run (to_list q) - let run_exn q = run_exn (to_list q) +module List = struct + let of_list l = OfSeq (Sequence.of_list l) + let to_list q = map Sequence.to_list (Reflect q) + let run q = run1 (to_list q) +end + +module Array = struct + let of_array a = OfSeq (Sequence.of_array a) + let to_array q = + map (fun s -> Array.of_list (Sequence.to_list s)) (Reflect q) + let run q = run1 (to_array q) end module AdaptSet(S : Set.S) = struct - let of_set set = - return (Coll.of_seq (fun k -> S.iter k set)) + let of_set set = OfSeq (fun k -> S.iter k set) let to_set q = - let f c = Sequence.fold (fun set x -> S.add x set) S.empty (Coll.to_seq c) in - query_map f q + let f c = Sequence.fold (fun set x -> S.add x set) S.empty c in + map f (reflect q) - let run q = run (to_set q) - let run_exn q = run_exn (to_set q) + let run q = run1 (to_set q) end module AdaptMap(M : Map.S) = struct let _to_seq m k = M.iter (fun x y -> k (x,y)) m - let of_map map = - return (Coll.of_seq (_to_seq map)) + let of_map map = OfSeq (_to_seq map) let to_pmap m = { PMap.get = (fun x -> try Some (M.find x m) with Not_found -> None); @@ -932,12 +786,11 @@ module AdaptMap(M : Map.S) = struct let to_map q = let f c = - Sequence.fold (fun m (x,y) -> M.add x y m) M.empty (Coll.to_seq c) + Sequence.fold (fun m (x,y) -> M.add x y m) M.empty c in - query_map f q + map f (reflect q) - let run q = run (to_map q) - let run_exn q = run_exn (to_map q) + let run q = run1 (to_map q) end module IO = struct @@ -991,16 +844,15 @@ module IO = struct let lines q = (* sequence of lines *) - let f s = Coll.of_seq (_lines s 0) in - query_map f q + let f s = _lines s 0 in + flat_map f q let lines' q = let f s = lazy (Sequence.to_list (_lines s 0)) in - lazy_ (query_map f q) + lazy_ (map f q) - let _join ~sep ?(stop="") l = + let _join ~sep ?(stop="") seq = let buf = Buffer.create 128 in - let seq = Coll.to_seq l in Sequence.iteri (fun i x -> if i>0 then Buffer.add_string buf sep; @@ -1011,18 +863,18 @@ module IO = struct let unlines q = let f l = lazy (_join ~sep:"\n" ~stop:"\n" l) in - lazy_ (query_map f q) + lazy_ (map f (reflect q)) let join sep q = let f l = lazy (_join ~sep l) in - lazy_ (query_map f q) + lazy_ (map f (reflect q)) let out oc q = - output_string oc (run_exn q) + output_string oc (run1 q) let out_lines oc q = - let x = run_exn q in - Sequence.iter (fun l -> output_string oc l; output_char oc '\n') (Coll.to_seq x) + let x = run q in + Sequence.iter (fun l -> output_string oc l; output_char oc '\n') x let to_file_exn filename q = _with_file_out filename (fun oc -> out oc q) diff --git a/src/advanced/CCLinq.mli b/src/advanced/CCLinq.mli index 3712b9f8..e5a2aa32 100644 --- a/src/advanced/CCLinq.mli +++ b/src/advanced/CCLinq.mli @@ -38,11 +38,11 @@ the order of execution. CCLinq.( of_list [1;2;3] - |> flat_map_l (fun x -> CCList.(x -- (x+10))) + |> flat_map (fun x -> Sequence.(x -- (x+10))) |> sort () |> count () - |> M.to_list - |> run_exn + |> flat_map PMap.to_seq + |> List.run );; - : (int * int) list = [(13, 1); (12, 2); (11, 3); (10, 3); (9, 3); (8, 3); (7, 3); (6, 3); (5, 3); (4, 3); (3, 3); (2, 2); (1, 1)] @@ -57,6 +57,8 @@ CCLinq.( - : `Ok () ]} +{b status: experimental} + *) type 'a sequence = ('a -> unit) -> unit @@ -65,214 +67,200 @@ type 'a ord = 'a -> 'a -> int type 'a hash = 'a -> int type 'a with_err = [`Ok of 'a | `Error of string ] -type 'a collection -(** Abstract type of collections of objects of type 'a. Those cannot - be used directly, they are to be processed using a query (type {!'a t}) - and converted to some list/sequence/array *) - (** {2 Polymorphic Maps} *) module PMap : sig type ('a, 'b) t val get : ('a,'b) t -> 'a -> 'b option - val get_exn : ('a,'b) t -> 'a -> 'b - (** Unsafe version of {!get}. - @raise Not_found if the element is not present *) - val size : (_,_) t -> int val to_seq : ('a, 'b) t -> ('a * 'b) sequence val to_list : ('a, 'b) t -> ('a * 'b) list - val to_coll : ('a, 'b) t -> ('a * 'b) collection + val map : ('b -> 'c) -> ('a, 'b) t -> ('a, 'c) t + (** Transform values *) + + val to_list : ('a,'b) t -> ('a*'b) list + + val reverse : ?cmp:'b ord -> ?eq:'b equal -> ?hash:'b hash -> unit -> + ('a,'b) t -> ('b,'a list) t + (** Reverse relation of the map, as a multimap *) + + val reverse_multimap : ?cmp:'b ord -> ?eq:'b equal -> ?hash:'b hash -> unit -> + ('a,'b list) t -> ('b,'a list) t + (** Reverse relation of the multimap *) + + val fold : ('acc -> 'a -> 'b -> 'acc) -> 'acc -> ('a,'b) t -> 'acc + (** Fold on the items of the map *) + + val fold_multimap : ('acc -> 'a -> 'b -> 'acc) -> 'acc -> + ('a,'b list) t -> 'acc + (** Fold on the items of the multimap *) + + val get_seq : 'a -> ('a, 'b) t -> 'b sequence + (** Select a key from a map and wrap into sequence *) + + val iter : ('a,'b) t -> ('a*'b) sequence + (** View a multimap as a proper collection *) + + val flatten : ('a,'b sequence) t -> ('a*'b) sequence + (** View a multimap as a collection of individual key/value pairs *) + + val flatten_l : ('a,'b list) t -> ('a*'b) sequence + (** View a multimap as a collection of individual key/value pairs *) end (** {2 Query operators} *) type 'a t -(** Type of a query that returns some value of type 'a *) +(** Type of a query that returns zero, one or more values of type 'a *) (** {6 Initial values} *) -val start : 'a -> 'a t -(** Start with a single value *) +val empty : 'a t +(** Empty collection *) -val of_list : 'a list -> 'a collection t +val start : 'a -> 'a t +(** Start with a single value + @deprecated since NEXT_RELEASE, use {!return} instead *) + +val return : 'a -> 'a t +(** Return one value *) + +val of_list : 'a list -> 'a t (** Query that just returns the elements of the list *) -val of_array : 'a array -> 'a collection t -val of_array_i : 'a array -> (int * 'a) collection t +val of_array : 'a array -> 'a t +val of_array_i : 'a array -> (int * 'a) t -val of_hashtbl : ('a,'b) Hashtbl.t -> ('a * 'b) collection t +val range : int -> int -> int t +(** [range i j] goes from [i] up to [j] included *) -val of_seq : 'a sequence -> 'a collection t +val (--) : int -> int -> int t +(** Synonym to {!range} *) + +val of_hashtbl : ('a,'b) Hashtbl.t -> ('a * 'b) t + +val of_seq : 'a sequence -> 'a t (** Query that returns the elements of the given sequence. *) -val of_queue : 'a Queue.t -> 'a collection t +val of_queue : 'a Queue.t -> 'a t -val of_stack : 'a Stack.t -> 'a collection t +val of_stack : 'a Stack.t -> 'a t -val of_string : string -> char collection t +val of_string : string -> char t (** Traverse the characters of the string *) (** {6 Execution} *) -val run : 'a t -> 'a with_err -(** Execute the query, possibly returning an error if things go wrong *) +val run : ?limit:int -> 'a t -> 'a sequence +(** Execute the query, possibly returning an error if things go wrong + @param limit max number of values to return *) -val run_exn : 'a t -> 'a -(** Execute the query, ignoring errors. Can raise an exception - if some execution step does. - @raise Failure if the query fails (or returns [`Error s]) *) +val run1 : 'a t -> 'a +(** Run the query and return the first value + @raise Not_found if the query succeeds with 0 elements *) -val run_no_optim : 'a t -> 'a with_err +val run_no_optim : ?limit:int -> 'a t -> 'a sequence (** Run without any optimization *) -(** {6 Basics on Collections} *) +(** {6 Basics} *) -val map : ('a -> 'b) -> 'a collection t -> 'b collection t +val map : ('a -> 'b) -> 'a t -> 'b t +(** map each value *) -val filter : ('a -> bool) -> 'a collection t -> 'a collection t +val (>|=) : 'a t -> ('a -> 'b) -> 'b t +(** Infix synonym of {!map} *) -val size : _ collection t -> int t +val filter : ('a -> bool) -> 'a t -> 'a t +(** Filter out values that do not satisfy predicate *) -val choose : 'a collection t -> 'a t -(** Choose one element (if any) in the collection. Fails - if the collections is empty *) +val size : _ t -> int t +(** [size t] returns one value, the number of items returned by [t] *) -val choose_err : 'a collection t -> 'a with_err t -(** Choose one element or fail explicitely *) +val choose : 'a t -> 'a t +(** Choose one element (if any, otherwise empty) in the collection. + This is like a "cut" in prolog. *) -val filter_map : ('a -> 'b option) -> 'a collection t -> 'b collection t +val filter_map : ('a -> 'b option) -> 'a t -> 'b t (** Filter and map elements at once *) -val flat_map : ('a -> 'b collection) -> 'a collection t -> 'b collection t -(** Monadic "bind", maps each element to a collection - and flatten the result *) - -val flat_map_seq : ('a -> 'b sequence) -> 'a collection t -> 'b collection t +val flat_map : ('a -> 'b sequence) -> 'a t -> 'b t (** Same as {!flat_map} but using sequences *) -val flat_map_l : ('a -> 'b list) -> 'a collection t -> 'b collection t +val flat_map_l : ('a -> 'b list) -> 'a t -> 'b t +(** map each element to a collection and flatten the result *) -val flatten : 'a collection collection t -> 'a collection t +val flat_map_l : ('a -> 'b list) -> 'a t -> 'b t -val flatten_l : 'a list collection t -> 'a collection t +val flatten : 'a list t -> 'a t -val take : int -> 'a collection t -> 'a collection t +val flatten_seq : 'a sequence t -> 'a t + +val take : int -> 'a t -> 'a t (** take at most [n] elements *) -val take_while : ('a -> bool) -> 'a collection t -> 'a collection t +val take_while : ('a -> bool) -> 'a t -> 'a t (** take elements while they satisfy a predicate *) -val sort : ?cmp:'a ord -> unit -> 'a collection t -> 'a collection t +val sort : ?cmp:'a ord -> unit -> 'a t -> 'a t (** Sort items by the given comparison function *) -val distinct : ?cmp:'a ord -> unit -> 'a collection t -> 'a collection t +val distinct : ?cmp:'a ord -> unit -> 'a t -> 'a t (** Remove duplicate elements from the input collection. All elements in the result are distinct. *) -(** {6 Queries on Maps} *) - -module M : sig - val get : 'a -> ('a, 'b) PMap.t t -> 'b t - (** Select a key from a map *) - - val get_err : 'a -> ('a, 'b) PMap.t t -> 'b with_err t - (** Explicit version of {!get}, with [`Error] if the key is not present *) - - val iter : ('a,'b) PMap.t t -> ('a*'b) collection t - (** View a multimap as a proper collection *) - - val flatten : ('a,'b collection) PMap.t t -> ('a*'b) collection t - (** View a multimap as a collection of individual key/value pairs *) - - val flatten' : ('a,'b list) PMap.t t -> ('a*'b) collection t - (** View a multimap as a collection of individual key/value pairs *) - - val map : ('b -> 'c) -> ('a, 'b) PMap.t t -> ('a, 'c) PMap.t t - (** Transform values *) - - val to_list : ('a,'b) PMap.t t -> ('a*'b) list t - - val reverse : ?cmp:'b ord -> ?eq:'b equal -> ?hash:'b hash -> unit -> - ('a,'b) PMap.t t -> ('b,'a list) PMap.t t - (** Reverse relation of the map, as a multimap *) - - val reverse_multimap : ?cmp:'b ord -> ?eq:'b equal -> ?hash:'b hash -> unit -> - ('a,'b list) PMap.t t -> ('b,'a list) PMap.t t - (** Reverse relation of the multimap *) - - val fold : ('acc -> 'a -> 'b -> 'acc) -> 'acc -> ('a,'b) PMap.t t -> 'acc t - (** Fold on the items of the map *) - - val fold_multimap : ('acc -> 'a -> 'b -> 'acc) -> 'acc -> - ('a,'b list) PMap.t t -> 'acc t - (** Fold on the items of the multimap *) -end - (** {6 Aggregation} *) val group_by : ?cmp:'b ord -> ?eq:'b equal -> ?hash:'b hash -> - ('a -> 'b) -> 'a collection t -> ('b,'a list) PMap.t t + ('a -> 'b) -> 'a t -> ('b,'a list) PMap.t t (** [group_by f] takes a collection [c] as input, and returns a multimap [m] such that for each [x] in [c], [x] occurs in [m] under the key [f x]. In other words, [f] is used to obtain a key from [x], and [x] is added to the multimap using this key. *) val group_by' : ?cmp:'b ord -> ?eq:'b equal -> ?hash:'b hash -> - ('a -> 'b) -> 'a collection t -> ('b * 'a list) collection t + ('a -> 'b) -> 'a t -> ('b * 'a list) t val count : ?cmp:'a ord -> ?eq:'a equal -> ?hash:'a hash -> - unit -> 'a collection t -> ('a, int) PMap.t t + unit -> 'a t -> ('a, int) PMap.t t (** [count c] returns a map from elements of [c] to the number of time those elements occur. *) -val count' : ?cmp:'a ord -> unit -> 'a collection t -> ('a * int) collection t +val count' : ?cmp:'a ord -> unit -> 'a t -> ('a * int) t -val fold : ('b -> 'a -> 'b) -> 'b -> 'a collection t -> 'b t +val fold : ('b -> 'a -> 'b) -> 'b -> 'a t -> 'b t (** Fold over the collection *) -val size : _ collection t -> int t -(** Count how many elements the collection contains *) - val reduce : ('a -> 'b) -> ('a -> 'b -> 'b) -> ('b -> 'c) -> - 'a collection t -> 'c t + 'a t -> 'c t (** [reduce start mix stop q] uses [start] on the first element of [q], and combine the result with following elements using [mix]. The final value is transformed using [stop]. *) -val reduce_err : ('a -> 'b) -> ('a -> 'b -> 'b) -> ('b -> 'c) -> - 'a collection t -> 'c with_err t -(** Same as {!reduce} but fails explicitely on empty collections. *) +val is_empty : 'a t -> bool t -val is_empty : 'a collection t -> bool t +val sum : int t -> int t -val sum : int collection t -> int t +val contains : ?eq:'a equal -> 'a -> 'a t -> bool t -val contains : ?eq:'a equal -> 'a -> 'a collection t -> bool t +val average : int t -> int t +val max : int t -> int t +val min : int t -> int t -val average : int collection t -> int t -val max : int collection t -> int t -val min : int collection t -> int t - -val average_err : int collection t -> int with_err t -val max_err : int collection t -> int with_err t -val min_err : int collection t -> int with_err t - -val for_all : ('a -> bool) -> 'a collection t -> bool t -val exists : ('a -> bool) -> 'a collection t -> bool t -val find : ('a -> bool) -> 'a collection t -> 'a option t -val find_map : ('a -> 'b option) -> 'a collection t -> 'b option t +val for_all : ('a -> bool) -> 'a t -> bool t +val exists : ('a -> bool) -> 'a t -> bool t +val find : ('a -> bool) -> 'a t -> 'a option t +val find_map : ('a -> 'b option) -> 'a t -> 'b option t (** {6 Binary Operators} *) val join : ?cmp:'key ord -> ?eq:'key equal -> ?hash:'key hash -> ('a -> 'key) -> ('b -> 'key) -> merge:('key -> 'a -> 'b -> 'c option) -> - 'a collection t -> 'b collection t -> 'c collection t + 'a t -> 'b t -> 'c t (** [join key1 key2 ~merge] is a binary operation that takes two collections [a] and [b], projects their elements resp. with [key1] and [key2], and combine @@ -281,49 +269,57 @@ val join : ?cmp:'key ord -> ?eq:'key equal -> ?hash:'key hash -> of values is discarded. *) val group_join : ?cmp:'a ord -> ?eq:'a equal -> ?hash:'a hash -> - ('b -> 'a) -> 'a collection t -> 'b collection t -> + ('b -> 'a) -> 'a t -> 'b t -> ('a, 'b list) PMap.t t (** [group_join key2] associates to every element [x] of the first collection, all the elements [y] of the second collection such that [eq x (key y)] *) -val product : 'a collection t -> 'b collection t -> ('a * 'b) collection t +val product : 'a t -> 'b t -> ('a * 'b) t (** Cartesian product *) -val append : 'a collection t -> 'a collection t -> 'a collection t +val append : 'a t -> 'a t -> 'a t (** Append two collections together *) val inter : ?cmp:'a ord -> ?eq:'a equal -> ?hash:'a hash -> unit -> - 'a collection t -> 'a collection t -> 'a collection t + 'a t -> 'a t -> 'a t (** Intersection of two collections. Each element will occur at most once in the result *) val union : ?cmp:'a ord -> ?eq:'a equal -> ?hash:'a hash -> unit -> - 'a collection t -> 'a collection t -> 'a collection t + 'a t -> 'a t -> 'a t (** Union of two collections. Each element will occur at most once in the result *) val diff : ?cmp:'a ord -> ?eq:'a equal -> ?hash:'a hash -> unit -> - 'a collection t -> 'a collection t -> 'a collection t + 'a t -> 'a t -> 'a t (** Set difference *) (** {6 Tuple and Options} *) (** Specialized projection operators *) -val fst : ('a * 'b) collection t -> 'a collection t +val fst : ('a * 'b) t -> 'a t -val snd : ('a * 'b) collection t -> 'b collection t +val snd : ('a * 'b) t -> 'b t -val map1 : ('a -> 'b) -> ('a * 'c) collection t -> ('b * 'c) collection t +val map1 : ('a -> 'b) -> ('a * 'c) t -> ('b * 'c) t -val map2 : ('a -> 'b) -> ('c * 'a) collection t -> ('c * 'b) collection t +val map2 : ('a -> 'b) -> ('c * 'a) t -> ('c * 'b) t -val flatten_opt : 'a option collection t -> 'a collection t +val flatten_opt : 'a option t -> 'a t (** Flatten the collection by removing options *) -val opt_unwrap : 'a option t -> 'a t -(** unwrap an option type. Fails if the option value is [None] *) +(** {6 Applicative} *) + +val pure : 'a -> 'a t +(** Synonym to {!return} *) + +val app : ('a -> 'b) t -> 'a t -> 'b t +(** Apply each function to each value *) + +val (<*>) : ('a -> 'b) t -> 'a t -> 'b t +(** Infix synonym to {!app} *) (** {6 Monad} @@ -336,57 +332,61 @@ val bind : ('a -> 'b t) -> 'a t -> 'b t val (>>=) : 'a t -> ('a -> 'b t) -> 'b t (** Infix version of {!bind} *) -val return : 'a -> 'a t -(** Synonym to {!start} *) - -val query_map : ('a -> 'b) -> 'a t -> 'b t -(** PMap results directly, rather than collections of elements *) - (** {6 Misc} *) -val catch : 'a with_err t -> 'a t -(** Catch errors within the execution itself. In other words, [run (catch q)] - with succeed with [x] if [q] succeeds with [`Ok x], and fail if [q] - succeeds with [`Error s] or if [q] fails *) - val lazy_ : 'a lazy_t t -> 'a t +val opt_unwrap : 'a option t -> 'a t + +val reflect : 'a t -> 'a sequence t +(** [reflect q] evaluates all values in [q] and returns a sequence + of all those values. Also blocks optimizations *) + +(** {6 Infix} *) + +module Infix : sig + val (>>=) : 'a t -> ('a -> 'b t) -> 'b t + val (>|=) : 'a t -> ('a -> 'b) -> 'b t + val (<*>) : ('a -> 'b) t -> 'a t -> 'b t + val (--) : int -> int -> int t +end + (** {6 Adapters} *) -val to_array : 'a collection t -> 'a array t -(** Build an array of results *) - -val to_seq : 'a collection t -> 'a sequence t +val to_seq : 'a t -> 'a sequence t (** Build a (re-usable) sequence of elements, which can then be converted into other structures *) -val to_hashtbl : ('a * 'b) collection t -> ('a, 'b) Hashtbl.t t +val to_hashtbl : ('a * 'b) t -> ('a, 'b) Hashtbl.t t (** Build a hashtable from the collection *) -val to_queue : 'a collection t -> ('a Queue.t -> unit) t +val to_queue : 'a t -> 'a Queue.t t -val to_stack : 'a collection t -> ('a Stack.t -> unit) t +val to_stack : 'a t -> 'a Stack.t t -module L : sig - val of_list : 'a list -> 'a collection t - val to_list : 'a collection t -> 'a list t - val run : 'a collection t -> 'a list with_err - val run_exn : 'a collection t -> 'a list +module List : sig + val of_list : 'a list -> 'a t + val to_list : 'a t -> 'a list t + val run : 'a t -> 'a list +end + +module Array : sig + val of_array : 'a array -> 'a t + val to_array : 'a t -> 'a array t + val run : 'a t -> 'a array end module AdaptSet(S : Set.S) : sig - val of_set : S.t -> S.elt collection t - val to_set : S.elt collection t -> S.t t - val run : S.elt collection t -> S.t with_err - val run_exn : S.elt collection t -> S.t + val of_set : S.t -> S.elt t + val to_set : S.elt t -> S.t t + val run : S.elt t -> S.t end module AdaptMap(M : Map.S) : sig - val of_map : 'a M.t -> (M.key * 'a) collection t + val of_map : 'a M.t -> (M.key * 'a) t val to_pmap : 'a M.t -> (M.key, 'a) PMap.t - val to_map : (M.key * 'a) collection t -> 'a M.t t - val run : (M.key * 'a) collection t -> 'a M.t with_err - val run_exn : (M.key * 'a) collection t -> 'a M.t + val to_map : (M.key * 'a) t -> 'a M.t t + val run : (M.key * 'a) t -> 'a M.t end module IO : sig @@ -400,19 +400,19 @@ module IO : sig (** Read a whole file (given by name) and return its content as a string *) - val lines : string t -> string collection t + val lines : string t -> string t (** Convert a string into a collection of lines *) val lines' : string t -> string list t (** Convert a string into a list of lines *) - val join : string -> string collection t -> string t + val join : string -> string t -> string t - val unlines : string collection t -> string t + val unlines : string t -> string t (** Join lines together *) val out : out_channel -> string t -> unit - val out_lines : out_channel -> string collection t -> unit + val out_lines : out_channel -> string t -> unit (** Evaluate the query and print it line by line on the output *) (** {8 Run methods} *) @@ -420,6 +420,6 @@ module IO : sig val to_file : string -> string t -> unit with_err val to_file_exn : string -> string t -> unit - val to_file_lines : string -> string collection t -> unit with_err - val to_file_lines_exn : string -> string collection t -> unit + val to_file_lines : string -> string t -> unit with_err + val to_file_lines_exn : string -> string t -> unit end