From: Dave B. <da...@ra...> - 2007-05-21 06:24:21
|
I was trying to write a PSet module (to translate some Haskell exercises that are a bit painful to write using the functor-style Set) and I realized that I was passing a lot of comparison functions around, even though in most cases they were the same comparison functions that are internally stored as the "cmp" field of PMap.t. Here's my (somewhat incomplete, but working) PSet: module PSet : sig type 'a t val empty : 'a t val is_empty : 'a t -> bool val create : ('a -> 'a -> int) -> 'a t val mem : 'a -> 'a t -> bool val add : 'a -> 'a t -> 'a t val singleton : ?cmp:('a -> 'a -> int) -> 'a -> 'a t val fold : ('a -> 'b -> 'b) -> 'a t -> 'b -> 'b val map : ?cmp:('b -> 'b -> int) -> ('a -> 'b) -> 'a t -> 'b t val filter : ?cmp:('a -> 'a -> int) -> ('a -> bool) -> 'a t -> 'a t val union : 'a t -> 'a t -> 'a t val compare : ?cmp:('a -> 'a -> int) -> 'a t -> 'a t -> int val elements : 'a t -> 'a list val of_list : ?cmp:('a -> 'a -> int) -> 'a list -> 'a t end = struct type 'a t = ('a, unit) PMap.t let empty = PMap.empty let is_empty = PMap.is_empty let create cmp = PMap.create cmp let mem = PMap.mem let add elt set = PMap.add elt () set let singleton ?(cmp=Pervasives.compare) elt = add elt (create cmp) let fold f set init = PMap.foldi (fun elt () acc -> f elt acc) set init let map ?(cmp=Pervasives.compare) f set = fold (fun elt acc -> add (f elt) acc) set (create cmp) let filter ?(cmp=Pervasives.compare) f set = fold (fun elt acc -> if f elt then add elt acc else acc) set (create cmp) let union set1 set2 = fold add set2 set1 let compare ?(cmp=Pervasives.compare) set1 set2 = let rec loop enum1 enum2 = match (Enum.get enum1, Enum.get enum2) with | (None, None) -> 0 | (None, _) -> -1 | (_, None) -> 1 | (Some (a, ()), Some (b, ())) -> match cmp a b with | 0 -> loop enum1 enum2 | c -> c in loop (PMap.enum set1) (PMap.enum set2) let elements set = fold (fun elt acc -> elt :: acc) set [] let of_list ?(cmp=Pervasives.compare) list = List.fold_right add list (create cmp) end There are a couple of cases where it would be nice to have access to the "cmp" field: "filter" and "compare" both ought to know what comparison function to use. In addition, I'd now like to add "inter" and "diff" functions and I'm contemplating writing them in terms of PMap.remove since I can hold onto the comparison function, even if it means removing every single item. Would it be too much of a break in abstraction to provide a function like "PMap.get_cmp" that would return the comparator? At one point I was using Obj.magic, but I felt guilty and rolled that back. =) Thanks, Dave |