* [Caml-list] Wrapping up the Set module in another @ 2014-03-26 15:58 John Whitington 2014-03-26 17:04 ` John Carr 2014-03-26 21:11 ` Leo White 0 siblings, 2 replies; 6+ messages in thread From: John Whitington @ 2014-03-26 15:58 UTC (permalink / raw) To: caml-list Hi, Suppose I want to benchmark various toy set implementations, so I have already written: module type SetType = sig type 'a t val set_of_list : 'a list -> 'a t val list_of_set : 'a t -> 'a list val insert : 'a -> 'a t -> 'a t val size : 'a t -> int val member : 'a -> 'a t -> bool end and then, for example: module SetList : sig include SetType end = struct type 'a t = 'a list let list_of_set x = x let rec set_of_list l = match l with [] -> [] | h::t -> if List.mem h t then set_of_list t else h :: set_of_list t let insert x l = x :: l let size = List.length let member = List.mem end This works fine -- I can put them into a little list, and run tests: let implementations = [("Lists", (module SetList : SetType)); ("Trees", (module SetTree : SetType)); ("Red-black trees", (module SetRedBlack : SetType)); ("Hash tables", (module SetHashtbl : SetType))] Now, it would be nice to include OCaml's Set module, but can it be made to fit the signature? So far I have: let make_setset (type s) () = let module SetSet : sig include SetType end = struct module S = Set.Make (struct type t = s let compare = compare end) type 'a t = S.t let list_of_set s = S.elements s let set_of_list l = List.fold_right S.add l S.empty let member = S.mem let insert = S.add let size = S.cardinal end in (module SetSet : SetType) and let implementations = let module SetSet = (val (make_setset ())) in [("Lists", (module SetList : SetType)); ("Trees", (module SetTree : SetType)); ("Red-black trees", (module SetRedBlack : SetType)); ("Hash tables", (module SetHashtbl : SetType)); ("OCaml sets", (module SetSet : SetType))] The problem here, it seems to me, is that the connection between 'a in make_setset and (type s) and S.elt is not established, and so the return types of list_of_set etc. don't type-check. Is there any way to do this, or is the functorised implementation of Set fundamentally opposed to the normal polymorphism of the type 'a t in SetType? Thanks, -- John Whitington Director, Coherent Graphics Ltd http://www.coherentpdf.com/ ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Caml-list] Wrapping up the Set module in another 2014-03-26 15:58 [Caml-list] Wrapping up the Set module in another John Whitington @ 2014-03-26 17:04 ` John Carr 2014-03-26 21:11 ` Leo White 1 sibling, 0 replies; 6+ messages in thread From: John Carr @ 2014-03-26 17:04 UTC (permalink / raw) To: John Whitington; +Cc: caml-list I think your distinction between types of polymorphism is correct. Set.S contains monomorphic functions. You want [forall] but Set.Make gives you [exists]. The library needs a different Set.OrderedType module for every type to be stored in a Set.S.t. You only create one such module per call to make_setset. > Hi, > > Suppose I want to benchmark various toy set implementations, so I have > already written: > > module type SetType = > sig > type 'a t > val set_of_list : 'a list -> 'a t > val list_of_set : 'a t -> 'a list > val insert : 'a -> 'a t -> 'a t > val size : 'a t -> int > val member : 'a -> 'a t -> bool > end > > and then, for example: > > module SetList : sig include SetType end = > struct > type 'a t = 'a list > > let list_of_set x = x > > let rec set_of_list l = > match l with > [] -> [] > | h::t -> > if List.mem h t then set_of_list t else h :: set_of_list t > > let insert x l = x :: l > > let size = List.length > > let member = List.mem > end > > This works fine -- I can put them into a little list, and run tests: > > let implementations = > [("Lists", (module SetList : SetType)); > ("Trees", (module SetTree : SetType)); > ("Red-black trees", (module SetRedBlack : SetType)); > ("Hash tables", (module SetHashtbl : SetType))] > > Now, it would be nice to include OCaml's Set module, but can it be > made to fit the signature? So far I have: > > let make_setset (type s) () = > let module SetSet : sig include SetType end = > struct > module S = Set.Make (struct type t = s let compare = compare end) > > type 'a t = S.t > > let list_of_set s = S.elements s > > let set_of_list l = List.fold_right S.add l S.empty > > let member = S.mem > > let insert = S.add > > let size = S.cardinal > end > in > (module SetSet : SetType) > > and > > let implementations = > let module SetSet = (val (make_setset ())) in > [("Lists", (module SetList : SetType)); > ("Trees", (module SetTree : SetType)); > ("Red-black trees", (module SetRedBlack : SetType)); > ("Hash tables", (module SetHashtbl : SetType)); > ("OCaml sets", (module SetSet : SetType))] > > The problem here, it seems to me, is that the connection between 'a in > make_setset and (type s) and S.elt is not established, and so the > return types of list_of_set etc. don't type-check. > > Is there any way to do this, or is the functorised implementation of > Set fundamentally opposed to the normal polymorphism of the type 'a t > in SetType? > > Thanks, > > -- > John Whitington > Director, Coherent Graphics Ltd > http://www.coherentpdf.com/ > > > -- > Caml-list mailing list. Subscription management and archives: > https://sympa.inria.fr/sympa/arc/caml-list > Beginner's list: http://groups.yahoo.com/group/ocaml_beginners > Bug reports: http://caml.inria.fr/bin/caml-bugs ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Caml-list] Wrapping up the Set module in another 2014-03-26 15:58 [Caml-list] Wrapping up the Set module in another John Whitington 2014-03-26 17:04 ` John Carr @ 2014-03-26 21:11 ` Leo White 2014-03-28 8:22 ` Thomas Braibant 1 sibling, 1 reply; 6+ messages in thread From: Leo White @ 2014-03-26 21:11 UTC (permalink / raw) To: John Whitington; +Cc: caml-list It is not at all ideal, and there is almost certainly a better way, but you could wrap the set module up with the actual set. I also don't know how much the overhead might affect your benchmarks. # module SetSet : SetType = struct module type SetS = sig include Set.S val s : t end;; type 'a t = (module SetS with type elt = 'a) let list_of_set (type elt) ((module S) : elt t) = S.elements S.s let set_of_list (type elt) (l : elt list) : elt t = (module struct include Set.Make (struct type t = elt let compare = compare end) let s = List.fold_right add l empty end) let member (type elt) (x : elt) ((module S) : elt t) = S.mem x S.s let insert (type elt) (x : elt) ((module S) : elt t) : elt t = (module struct include S let s = add x S.s end) let size (type elt) ((module S) : elt t) = S.cardinal S.s end;; module SetSet : SetType # let implementations = [("Lists", (module SetList : SetType)); ("Sets", (module SetSet : SetType))];; val implementations : (string * (module SetType)) list = [("Lists", <module>); ("Sets", <module>)] Regards, Leo John Whitington <john@coherentgraphics.co.uk> writes: > Hi, > > Suppose I want to benchmark various toy set implementations, so I have already written: > > module type SetType = > sig > type 'a t > val set_of_list : 'a list -> 'a t > val list_of_set : 'a t -> 'a list > val insert : 'a -> 'a t -> 'a t > val size : 'a t -> int > val member : 'a -> 'a t -> bool > end > > and then, for example: > > module SetList : sig include SetType end = > struct > type 'a t = 'a list > > let list_of_set x = x > > let rec set_of_list l = > match l with > [] -> [] > | h::t -> > if List.mem h t then set_of_list t else h :: set_of_list t > > let insert x l = x :: l > > let size = List.length > > let member = List.mem > end > > This works fine -- I can put them into a little list, and run tests: > > let implementations = > [("Lists", (module SetList : SetType)); > ("Trees", (module SetTree : SetType)); > ("Red-black trees", (module SetRedBlack : SetType)); > ("Hash tables", (module SetHashtbl : SetType))] > > Now, it would be nice to include OCaml's Set module, but can it be made to fit the signature? So far I have: > > let make_setset (type s) () = > let module SetSet : sig include SetType end = > struct > module S = Set.Make (struct type t = s let compare = compare end) > > type 'a t = S.t > > let list_of_set s = S.elements s > > let set_of_list l = List.fold_right S.add l S.empty > > let member = S.mem > > let insert = S.add > > let size = S.cardinal > end > in > (module SetSet : SetType) > > and > > let implementations = > let module SetSet = (val (make_setset ())) in > [("Lists", (module SetList : SetType)); > ("Trees", (module SetTree : SetType)); > ("Red-black trees", (module SetRedBlack : SetType)); > ("Hash tables", (module SetHashtbl : SetType)); > ("OCaml sets", (module SetSet : SetType))] > > The problem here, it seems to me, is that the connection between 'a in make_setset and (type s) and S.elt is not > established, and so the return types of list_of_set etc. don't type-check. > > Is there any way to do this, or is the functorised implementation of Set fundamentally opposed to the normal > polymorphism of the type 'a t in SetType? > > Thanks, > > -- > John Whitington > Director, Coherent Graphics Ltd > http://www.coherentpdf.com/ ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Caml-list] Wrapping up the Set module in another 2014-03-26 21:11 ` Leo White @ 2014-03-28 8:22 ` Thomas Braibant 2014-04-03 14:28 ` Leo White 0 siblings, 1 reply; 6+ messages in thread From: Thomas Braibant @ 2014-03-28 8:22 UTC (permalink / raw) To: Leo White; +Cc: John Whitington, caml-list Hi, I really like this trick of wrapping the module and an actual set together. Do you have any idea of the runtime cost? I remember reading that functor applications are runtime operations, but I wonder what is the overhead. Best Thomas On Wed, Mar 26, 2014 at 9:11 PM, Leo White <lpw25@cam.ac.uk> wrote: > It is not at all ideal, and there is almost certainly a better way, but > you could wrap the set module up with the actual set. I also don't know > how much the overhead might affect your benchmarks. > > # module SetSet : SetType = struct > module type SetS = sig include Set.S val s : t end;; > > type 'a t = (module SetS with type elt = 'a) > > let list_of_set (type elt) ((module S) : elt t) = S.elements S.s > > let set_of_list (type elt) (l : elt list) : elt t = > (module struct > include Set.Make (struct type t = elt let compare = compare end) > let s = List.fold_right add l empty > end) > > let member (type elt) (x : elt) ((module S) : elt t) = S.mem x S.s > > let insert (type elt) (x : elt) ((module S) : elt t) : elt t = > (module struct > include S > let s = add x S.s > end) > > let size (type elt) ((module S) : elt t) = S.cardinal S.s > > end;; > module SetSet : SetType > > # let implementations = > [("Lists", (module SetList : SetType)); > ("Sets", (module SetSet : SetType))];; > val implementations : (string * (module SetType)) list = > [("Lists", <module>); ("Sets", <module>)] > > Regards, > > Leo > > John Whitington <john@coherentgraphics.co.uk> writes: > >> Hi, >> >> Suppose I want to benchmark various toy set implementations, so I have already written: >> >> module type SetType = >> sig >> type 'a t >> val set_of_list : 'a list -> 'a t >> val list_of_set : 'a t -> 'a list >> val insert : 'a -> 'a t -> 'a t >> val size : 'a t -> int >> val member : 'a -> 'a t -> bool >> end >> >> and then, for example: >> >> module SetList : sig include SetType end = >> struct >> type 'a t = 'a list >> >> let list_of_set x = x >> >> let rec set_of_list l = >> match l with >> [] -> [] >> | h::t -> >> if List.mem h t then set_of_list t else h :: set_of_list t >> >> let insert x l = x :: l >> >> let size = List.length >> >> let member = List.mem >> end >> >> This works fine -- I can put them into a little list, and run tests: >> >> let implementations = >> [("Lists", (module SetList : SetType)); >> ("Trees", (module SetTree : SetType)); >> ("Red-black trees", (module SetRedBlack : SetType)); >> ("Hash tables", (module SetHashtbl : SetType))] >> >> Now, it would be nice to include OCaml's Set module, but can it be made to fit the signature? So far I have: >> >> let make_setset (type s) () = >> let module SetSet : sig include SetType end = >> struct >> module S = Set.Make (struct type t = s let compare = compare end) >> >> type 'a t = S.t >> >> let list_of_set s = S.elements s >> >> let set_of_list l = List.fold_right S.add l S.empty >> >> let member = S.mem >> >> let insert = S.add >> >> let size = S.cardinal >> end >> in >> (module SetSet : SetType) >> >> and >> >> let implementations = >> let module SetSet = (val (make_setset ())) in >> [("Lists", (module SetList : SetType)); >> ("Trees", (module SetTree : SetType)); >> ("Red-black trees", (module SetRedBlack : SetType)); >> ("Hash tables", (module SetHashtbl : SetType)); >> ("OCaml sets", (module SetSet : SetType))] >> >> The problem here, it seems to me, is that the connection between 'a in make_setset and (type s) and S.elt is not >> established, and so the return types of list_of_set etc. don't type-check. >> >> Is there any way to do this, or is the functorised implementation of Set fundamentally opposed to the normal >> polymorphism of the type 'a t in SetType? >> >> Thanks, >> >> -- >> John Whitington >> Director, Coherent Graphics Ltd >> http://www.coherentpdf.com/ > > -- > Caml-list mailing list. Subscription management and archives: > https://sympa.inria.fr/sympa/arc/caml-list > Beginner's list: http://groups.yahoo.com/group/ocaml_beginners > Bug reports: http://caml.inria.fr/bin/caml-bugs ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Caml-list] Wrapping up the Set module in another 2014-03-28 8:22 ` Thomas Braibant @ 2014-04-03 14:28 ` Leo White 2014-04-03 20:31 ` [Caml-list] More efficient compilation of functors? (was: Wrapping up the Set module in another) Alain Frisch 0 siblings, 1 reply; 6+ messages in thread From: Leo White @ 2014-04-03 14:28 UTC (permalink / raw) To: Thomas Braibant; +Cc: John Whitington, caml-list I'm afraid I don't have any real idea of the runtime cost. The main additional cost would come from calling `Set.Make` in `set_of_list` and creating new modules in `set_of_list` and `insert`. `Set.Make` has to create a lot of closures which capture the `compare` function. I think these closures are all allocated at once, but this still means a lot of assignments. Creating the new modules is a record allocation and assignment of all the record fields. The cost of creating modules could probably be reduced a bit by rewriting it as: module type SetS = sig module Ops : Set.S val s : Ops.t end;; type 'a t = (module SetS with type Ops.elt = 'a) let list_of_set (type elt) ((module S) : elt t) = S.Ops.elements S.s let set_of_list (type elt) (l : elt list) : elt t = (module struct module Ops = Set.Make (struct type t = elt let compare = compare end) let s = List.fold_right Ops.add l Ops.empty end) let member (type elt) (x : elt) ((module S) : elt t) = S.Ops.mem x S.s let insert (type elt) (x : elt) ((module S) : elt t) : elt t = (module struct module Ops = S.Ops let s = add x S.s end) let size (type elt) ((module S) : elt t) = S.Ops.cardinal S.s There would also be a cost in the other functions for the indirection to get to the actual set and the functions. Theoretically it might also be slower than using the result of `Set.Make` directly since that would be easier for the compiler to optimise by calling the functions directly or inlining them, although I'm not sure if the current compiler actually does this. Regards, Leo Thomas Braibant <thomas.braibant@gmail.com> writes: > Hi, > > I really like this trick of wrapping the module and an actual set > together. Do you have any idea of the runtime cost? I remember reading > that functor applications are runtime operations, but I wonder what is > the overhead. > > Best > Thomas > > On Wed, Mar 26, 2014 at 9:11 PM, Leo White <lpw25@cam.ac.uk> wrote: >> It is not at all ideal, and there is almost certainly a better way, but >> you could wrap the set module up with the actual set. I also don't know >> how much the overhead might affect your benchmarks. >> >> # module SetSet : SetType = struct >> module type SetS = sig include Set.S val s : t end;; >> >> type 'a t = (module SetS with type elt = 'a) >> >> let list_of_set (type elt) ((module S) : elt t) = S.elements S.s >> >> let set_of_list (type elt) (l : elt list) : elt t = >> (module struct >> include Set.Make (struct type t = elt let compare = compare end) >> let s = List.fold_right add l empty >> end) >> >> let member (type elt) (x : elt) ((module S) : elt t) = S.mem x S.s >> >> let insert (type elt) (x : elt) ((module S) : elt t) : elt t = >> (module struct >> include S >> let s = add x S.s >> end) >> >> let size (type elt) ((module S) : elt t) = S.cardinal S.s >> >> end;; >> module SetSet : SetType >> >> # let implementations = >> [("Lists", (module SetList : SetType)); >> ("Sets", (module SetSet : SetType))];; >> val implementations : (string * (module SetType)) list = >> [("Lists", <module>); ("Sets", <module>)] >> >> Regards, >> >> Leo >> >> John Whitington <john@coherentgraphics.co.uk> writes: >> >>> Hi, >>> >>> Suppose I want to benchmark various toy set implementations, so I have already written: >>> >>> module type SetType = >>> sig >>> type 'a t >>> val set_of_list : 'a list -> 'a t >>> val list_of_set : 'a t -> 'a list >>> val insert : 'a -> 'a t -> 'a t >>> val size : 'a t -> int >>> val member : 'a -> 'a t -> bool >>> end >>> >>> and then, for example: >>> >>> module SetList : sig include SetType end = >>> struct >>> type 'a t = 'a list >>> >>> let list_of_set x = x >>> >>> let rec set_of_list l = >>> match l with >>> [] -> [] >>> | h::t -> >>> if List.mem h t then set_of_list t else h :: set_of_list t >>> >>> let insert x l = x :: l >>> >>> let size = List.length >>> >>> let member = List.mem >>> end >>> >>> This works fine -- I can put them into a little list, and run tests: >>> >>> let implementations = >>> [("Lists", (module SetList : SetType)); >>> ("Trees", (module SetTree : SetType)); >>> ("Red-black trees", (module SetRedBlack : SetType)); >>> ("Hash tables", (module SetHashtbl : SetType))] >>> >>> Now, it would be nice to include OCaml's Set module, but can it be made to fit the signature? So far I have: >>> >>> let make_setset (type s) () = >>> let module SetSet : sig include SetType end = >>> struct >>> module S = Set.Make (struct type t = s let compare = compare end) >>> >>> type 'a t = S.t >>> >>> let list_of_set s = S.elements s >>> >>> let set_of_list l = List.fold_right S.add l S.empty >>> >>> let member = S.mem >>> >>> let insert = S.add >>> >>> let size = S.cardinal >>> end >>> in >>> (module SetSet : SetType) >>> >>> and >>> >>> let implementations = >>> let module SetSet = (val (make_setset ())) in >>> [("Lists", (module SetList : SetType)); >>> ("Trees", (module SetTree : SetType)); >>> ("Red-black trees", (module SetRedBlack : SetType)); >>> ("Hash tables", (module SetHashtbl : SetType)); >>> ("OCaml sets", (module SetSet : SetType))] >>> >>> The problem here, it seems to me, is that the connection between 'a in make_setset and (type s) and S.elt is not >>> established, and so the return types of list_of_set etc. don't type-check. >>> >>> Is there any way to do this, or is the functorised implementation of Set fundamentally opposed to the normal >>> polymorphism of the type 'a t in SetType? >>> >>> Thanks, >>> >>> -- >>> John Whitington >>> Director, Coherent Graphics Ltd >>> http://www.coherentpdf.com/ >> >> -- >> Caml-list mailing list. Subscription management and archives: >> https://sympa.inria.fr/sympa/arc/caml-list >> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners >> Bug reports: http://caml.inria.fr/bin/caml-bugs ^ permalink raw reply [flat|nested] 6+ messages in thread
* [Caml-list] More efficient compilation of functors? (was: Wrapping up the Set module in another) 2014-04-03 14:28 ` Leo White @ 2014-04-03 20:31 ` Alain Frisch 0 siblings, 0 replies; 6+ messages in thread From: Alain Frisch @ 2014-04-03 20:31 UTC (permalink / raw) To: Leo White, Thomas Braibant; +Cc: John Whitington, caml-list On 4/3/2014 4:28 PM, Leo White wrote: > The main additional cost would come from calling `Set.Make` in > `set_of_list` and creating new modules in `set_of_list` and `insert`. > `Set.Make` has to create a lot of closures which capture the `compare` > function. I think these closures are all allocated at once, but this > still means a lot of assignments. Creating the new modules is a record > allocation and assignment of all the record fields. I'm wondering whether an alternative compilation scheme could make functor instantiation much faster. Instead of having individual closures for all (non-closed) functions the functor exports, one could create a single big closure representing all functions at once. It would typically contain the functor's argument itself, plus other non functional values computed during the functor's body initialization (or maybe one could even keep a reference to the block representing the functor's result). The closure would be allocated at the beginning (with dummy values) and filled along the evaluation of the body. -- Alain ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2014-04-03 20:31 UTC | newest] Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2014-03-26 15:58 [Caml-list] Wrapping up the Set module in another John Whitington 2014-03-26 17:04 ` John Carr 2014-03-26 21:11 ` Leo White 2014-03-28 8:22 ` Thomas Braibant 2014-04-03 14:28 ` Leo White 2014-04-03 20:31 ` [Caml-list] More efficient compilation of functors? (was: Wrapping up the Set module in another) Alain Frisch
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox