caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [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;
as well as URLs for NNTP newsgroup(s).