caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Ollie Frolovs <of12343@my.bristol.ac.uk>
To: caml users <caml-list@inria.fr>
Cc: David House <dhouse@janestreet.com>,
	Yaron Minsky <yminsky@janestreet.com>,
	Mark Shinwell <mshinwell@janestreet.com>,
	Malcolm Matalka <mmatalka@gmail.com>
Subject: Re: [Caml-list] Creating a Map from custom type
Date: Fri, 15 Nov 2013 09:36:20 +0000	[thread overview]
Message-ID: <2AB0CEC4-E3FF-47B1-8554-612BE4CDBB26@my.bristol.ac.uk> (raw)
In-Reply-To: <CAK=fH+j6L3BD5nswGrH6_8Yw9J3WSY4mJTnsYXbV-GJPuP_dbA@mail.gmail.com>

Thank you David, Yaron, Mark & Malcolm! 

I managed to replace the associative list with a map and now my OCaml implementation of "Dynamic Programming Treatment of the Travelling Salesman Problem” (Bellman, 1961) can easily handle N=20 which is more than enough for my project since i'm using clustering techniques to split the graph into subgraphs. I also learned a lot about modules, interfaces, maps and even the basics of functors. So much to learn still! 

Thanks again.

— Ollie

On 14 Nov 2013, at 12:11, David House <dhouse@janestreet.com> wrote:

> To follow up on Mark's example, you can use the following slightly
> more general idiom:
> 
> module My_thing = struct
>  module T = struct
>    type t = int * string * string with sexp, compare
>  end
>  include T
>  include Comparable.Make(T)
> 
>  let do_some_stuff t = ...
> end
> 
> Then My_thing will satisfy the Comparable signature, which means
> you'll have My_thing.Map, as well as My_thing.Set, My_thing.equal,
> My_thing.(<) etc.
> 
> We do this on basically every type in core, since you'll want to use
> everything in a set sooner or later :)
> 
> The "gold standard" for such types is the Identifiable signature. This
> is basically the union of the Comparable signature, the Hashable
> signature (which gives you hashtables, hash-sets etc.) and the
> Stringable signature (to/from strings). You can get there with just a
> little more work:
> 
> module My_thing = struct
>  module T = struct
>    type t = ... with sexp, compare, bin_io
>    let hash = Hashtbl.hash
>    let to_string t = ...
>    let of_string t = ...
>    let module_name = "My_lib.My_thing" (* for the toplevel *)
>  end
>  include T
>  include Identifiable.Make(T)
> 
>  (* other functions here *)
> end
> 
> If you want the string representation to be the same as the sexp
> representation, that's possible too with only a little more
> clunkiness:
> 
> module My_thing = struct
>  module T = struct
>    module T' = struct
>      type t = ... with sexp, compare, bin_io
>    end
>    include T'
>    include Sexpable.To_stringable(T')
>    let hash = Hashtbl.hash
>    let module_name = "My_lib.My_thing" (* for the toplevel *)
>  end
>  include T
>  include Identifiable.Make(T)
> 
> (* other functions here *)
> end
> 
> On 14 November 2013 12:03, Yaron Minsky <yminsky@janestreet.com> wrote:
>> It's worth noting that if you want a simply polymorphic map, you can
>> have one, you just need to be explicit about what you're doing:
>> 
>> utop # let map = Map.Poly.of_alist_exn [1, "one"; 2, "two"; 3, "three"];;
>> val map : (int, string) Map.Poly.t = <abstr>
>> 
>> which is probably the lowest-pain approach.  Polymorphic compare
>> (which is what this is based on) has some downside, but is perfectly
>> good for many use-cases.  RWO covers in detail the pitfalls of
>> polymorphic compare, but it doesn't mean you should avoid it,
>> especially when you're getting started.
>> 
>> As for David's point about Core vs the stdlib, I think creating a map
>> with a polymorphic comparison function is actually quite a bit easier
>> in Core than it is with the stdlib, since no functor application is
>> required.
>> 
>> y
>> 
>> On Thu, Nov 14, 2013 at 6:21 AM, Mark Shinwell <mshinwell@janestreet.com> wrote:
>>> On 14 November 2013 10:39, Ollie Frolovs <of12343@my.bristol.ac.uk> wrote:
>>>> My current implementation uses associative lists, in subroute.ml:
>>>> 
>>>> open Core.Std
>>>> type t = ((int list * int) * (int * int list)) list
>>>> let empty = []
>>>> let to_list x = x
>>>> let add t k v = List.Assoc.add t k v
>>>> let find t k = List.Assoc.find t k
>>>> 
>>>> I would like to use a Map instead. The key for my Map must have the type (int list * int) and the values have the type (int * int list). If i understood it correctly, because the key is a tuple and not one of the built-in simple data types (string, int, etc), because of this i have to provide a custom comparator. This is first thing that i am not sure of.
>>> 
>>> I think you need something like:
>>> 
>>> module Key = struct
>>>  type t = int list * int with sexp, compare
>>> end
>>> 
>>> module My_map = Map.Make (Key)
>>> 
>>> Then, for example:
>>> 
>>>  let map =
>>>    My_map.add My_map.empty
>>>      ~key:([42], 0)
>>>      ~data:(1, [2])
>>> 
>>> The "with compare" auto-generates a "compare" function for
>>> you.  Using explicit comparison functions, as Core strongly
>>> encourages, does unfortunately mean a bit more code at times
>>> but is arguably vastly more sustainable as your codebase
>>> grows.  In such scenarios it becomes increasingly unlikely
>>> that the correct notion of comparison on one of your many
>>> abstract types coincides with the structural comparison
>>> on whatever implementation those types happen to have today.
>>> 
>>> Mark
>>> 
>>> --
>>> 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
>> 
>> --
>> 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


      reply	other threads:[~2013-11-15  9:36 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-11-14 10:39 Ollie Frolovs
2013-11-14 10:56 ` David Allsopp
2013-11-14 11:02 ` Malcolm Matalka
2013-11-14 11:21 ` Mark Shinwell
2013-11-14 12:03   ` Yaron Minsky
2013-11-14 12:11     ` David House
2013-11-15  9:36       ` Ollie Frolovs [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=2AB0CEC4-E3FF-47B1-8554-612BE4CDBB26@my.bristol.ac.uk \
    --to=of12343@my.bristol.ac.uk \
    --cc=caml-list@inria.fr \
    --cc=dhouse@janestreet.com \
    --cc=mmatalka@gmail.com \
    --cc=mshinwell@janestreet.com \
    --cc=yminsky@janestreet.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).