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
prev parent 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).