Mailing list for all users of the OCaml language and system.
 help / color / mirror / Atom feed
From: Markus Mottl <markus@oefai.at>
To: Michal Moskal <malekith@pld-linux.org>,
	Richard Jones <rich@annexia.org>,
	Claudio Sacerdoti Coen <sacerdot@cs.unibo.it>
Cc: ocaml-lib-devel@lists.sourceforge.net, caml-list@inria.fr
Subject: [Caml-list] Re: [Ocaml-lib-devel] pMap.ml
Date: Mon, 6 Oct 2003 18:56:00 +0200	[thread overview]
Message-ID: <20031006165600.GB2594@fichte.ai.univie.ac.at> (raw)
In-Reply-To: <20031006125246.GA25703@cs.unibo.it> <20031006115403.GA13493@redhat.com> <20031006114114.GA12034@roke.freak>

[-- Attachment #1: Type: text/plain, Size: 2292 bytes --]

On Mon, 06 Oct 2003, Michal Moskal wrote:
> On Mon, Oct 06, 2003 at 01:33:18PM +0200, Nicolas Cannasse wrote:
> > Manipulating references is most of the time quite a pain, and make the code
> > quite ugly.
> > I understand in some cases the need of pure functional data structure (Coq
> > code proof) but in the "average user" cases that target ExtLib, having a
> > mutable structure is surely better. For example I often use an Hashtable
> > where a Map would be better for theses two reasons :
> > - no need to define a module type (this is corrected by this polymorphic
> > version)
> > - the hashtable is mutable ! means, easy to use.
> 
> FWIW implementing mutable map on top of non-mutable one is easier and
> more efficient then vice versa. Just need to use ref. Otherwise you need
> to do some copy() tricks.

I completely agree with Michal here: it's essentially impossible to get
rid of the imperativeness of a datastructure unless you use some tricks
like monads that hide the state. Probably not what the "average user"
wants to work with :-)

On Mon, 06 Oct 2003, Richard Jones wrote:
> Hashtbls are much easier to use than Maps precisely for the reasons he
> has outlined. They'd be even better if the language offered syntactic
> support for them (but this just reflects my Perl background), eg:

Note that you can always easily implement the functionality of Hashtbls
using (purely functional) Maps and references - but not easily the other
way round! See attachment for an implementation. I haven't tested the
Hashtbl-code, but have used type annotations to have the code verified
a bit more tightly. Furthermore, I have updated pMap.ml, because, as I
have found out, its functional interface was incompatible with the on
in Map and also lacked functions.

On Mon, 06 Oct 2003, Claudio Sacerdoti Coen wrote:
>  Most of the time, mutable means non-reentrant.
>  This point should never be forgot when considering pros and cons
>  of an implementation. Expecially when dealing with proposed
>  "standard" libraries for a multi-threaded programming language.

Which is another very good argument against impure structures that don't
benefit from impurity in terms of efficiency...

Regards,
Markus

-- 
Markus Mottl          http://www.oefai.at/~markus          markus@oefai.at

[-- Attachment #2: pMap.ml --]
[-- Type: text/plain, Size: 4271 bytes --]

(*
 * pMap - Polymorphic maps
 * Copyright (C) 2003 Markus Mottl
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *)

type ('k, 'v) map =
  | Empty
  | Node of ('k, 'v) map * 'k * 'v * ('k, 'v) map * int

type ('k, 'v) t =
  {
    cmp : 'k -> 'k -> int;
    map : ('k, 'v) map;
  }

let height = function
  | Node (_, _, _, _, h) -> h
  | Empty -> 0

let make l k v r = Node (l, k, v, r, max (height l) (height r) + 1)

let bal l k v r =
  let hl = height l in
  let hr = height r in
  if hl > hr + 2 then
    match l with
    | Node (ll, lk, lv, lr, _) ->
        if height ll >= height lr then make ll lk lv (make lr k v r)
        else
          (match lr with
          | Node (lrl, lrk, lrv, lrr, _) ->
              make (make ll lk lv lrl) lrk lrv (make lrr k v r)
          | Empty -> assert false)
    | Empty -> assert false
  else if hr > hl + 2 then
    match r with
    | Node (rl, rk, rv, rr, _) ->
        if height rr >= height rl then make (make l k v rl) rk rv rr
        else
          (match rl with
          | Node (rll, rlk, rlv, rlr, _) ->
              make (make l k v rll) rlk rlv (make rlr rk rv rr)
          | Empty -> assert false)
    | Empty -> assert false
  else Node (l, k, v, r, max hl hr + 1)

let rec merge t1 t2 =
  match t1, t2 with
  | Node (l1, k1, v1, r1, _), Node (l2, k2, v2, r2, _) ->
      bal l1 k1 v1 (bal (merge r1 l2) k2 v2 r2)
  | Empty, t -> t
  | t, Empty -> t

let create cmp = { cmp = cmp; map = Empty }
let empty = { cmp = compare; map = Empty }

let add x d { cmp = cmp; map = map } =
  let rec loop = function
    | Node (l, k, v, r, h) ->
        let c = cmp x k in
        if c = 0 then Node (l, x, d, r, h)
        else if c < 0 then
          let nl = loop l in
          bal nl k v r
        else
          let nr = loop r in
          bal l k v nr
    | Empty -> Node (Empty, x, d, Empty, 1) in
  { cmp = cmp; map = loop map }

let find x { cmp = cmp; map = map } =
  let rec loop = function
    | Node (l, k, v, r, _) ->
        let c = cmp x k in
        if c < 0 then loop l
        else if c > 0 then loop r
        else v
    | Empty -> raise Not_found in
  loop map

let remove x { cmp = cmp; map = map } =
  let rec loop = function
    | Node (l, k, v, r, _) ->
        let c = cmp x k in
        if c = 0 then merge l r else
        if c < 0 then bal (loop l) k v r else bal l k v (loop r)
    | Empty -> Empty in
  { cmp = cmp; map = loop map }

let mem x { cmp = cmp; map = map } =
  let rec loop = function
    | Node (l, k, v, r, _) ->
        let c = cmp x k in
        c = 0 || loop (if c < 0 then l else r)
    | Empty -> false in
  loop map

let iter f { map = map } =
  let rec loop = function
    | Empty -> ()
    | Node (l, k, v, r, _) -> loop l; f k v; loop r in
  loop map

let map f { cmp = cmp; map = map } =
  let rec loop = function
    | Empty -> Empty
    | Node (l, k, v, r, h) -> Node (loop l, k, f v, loop r, h) in
  { cmp = cmp; map = loop map }

let mapi f { cmp = cmp; map = map } =
  let rec loop = function
    | Empty -> Empty
    | Node (l, k, v, r, h) -> Node (loop l, k, f k v, loop r, h) in
  { cmp = cmp; map = loop map }

let fold f { cmp = cmp; map = map } acc =
  let rec loop acc = function
    | Empty -> acc
    | Node (l, k, v, r, _) -> loop l (f k v (loop r acc)) in
  loop acc map

let enum m =
  let rec to_list acc = function
    | Empty -> acc
    | Node (l, k, v, r, _) -> to_list ((k, v) :: to_list acc r) l in
  ExtList.List.enum (to_list [] m.map)

let uncurry_add (k, v) m = add k v m
let of_enum ?(cmp = compare) e = Enum.fold uncurry_add (create cmp) e

[-- Attachment #3: hashtbl.ml --]
[-- Type: text/plain, Size: 1399 bytes --]

type ('k, 'v) t = ('k, 'v list ref) PMap.t ref

let create () : ('k, 'v) t = ref PMap.empty
let clear (m_ref : ('k, 'v) t) : unit = m_ref := PMap.empty

let add (m_ref : ('k, 'v) t) (x : 'k) (d : 'v) : unit =
  try
    let vlst_ref = PMap.find x !m_ref in
    vlst_ref := d :: !vlst_ref
  with Not_found -> m_ref := PMap.add x (ref [d]) !m_ref

let copy_ref r = ref !r
let copy (m_ref : ('k, 'v) t) : ('k, 'v) t = ref (PMap.map copy_ref !m_ref)
let find (m_ref : ('k, 'v) t) (x : 'k) : 'v = List.hd !(PMap.find x !m_ref)
let find_all m_ref x : 'v list = !(PMap.find x !m_ref)
let mem (m_ref : ('k, 'v) t) (x : 'k) : bool = PMap.mem x !m_ref

let remove (m_ref : ('k, 'v) t) (x : 'k) : unit =
  try
    let vlst_ref = PMap.find x !m_ref in
    match !vlst_ref with
    | [_] -> m_ref := PMap.remove x !m_ref
    | _ :: rest -> vlst_ref := rest
    | [] -> assert false
  with Not_found -> ()

let replace (m_ref : ('a, 'b) t) x d =
  try
    let vlst_ref = PMap.find x !m_ref in
    vlst_ref := d :: List.tl !vlst_ref
  with Not_found -> m_ref := PMap.add x (ref [d]) !m_ref

let iter (f : 'k -> 'v -> unit) (m_ref : ('k, 'v) t) : unit =
  let f' k vlst_ref = List.iter (f k) !vlst_ref in
  PMap.iter f' !m_ref

let fold (f : 'k -> 'v -> 'a -> 'a) (m_ref : ('k, 'v) t) (acc : 'a) : 'a =
  let f' k vlst_ref acc =
    List.fold_left (fun acc v -> f k v acc) acc !vlst_ref in
  PMap.fold f' !m_ref acc

      parent reply	other threads:[~2003-10-06 16:56 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20031005154938.GB31811@fichte.ai.univie.ac.at>
     [not found] ` <20031006083236.GA8512@redhat.com>
     [not found]   ` <20031006090209.GA2594@fichte.ai.univie.ac.at>
     [not found]     ` <008901c38bfd$aa08b530$6f01a8c0@PWARP>
2003-10-06 11:54       ` Richard Jones
2003-10-06 12:06         ` Stefano Zacchiroli
2003-10-07 16:37           ` brogoff
2003-10-07 20:16             ` skaller
     [not found]         ` <20031006114114.GA12034@roke.freak>
     [not found]           ` <20031006125246.GA25703@cs.unibo.it>
2003-10-06 16:56             ` Markus Mottl [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=20031006165600.GB2594@fichte.ai.univie.ac.at \
    --to=markus@oefai.at \
    --cc=caml-list@inria.fr \
    --cc=malekith@pld-linux.org \
    --cc=ocaml-lib-devel@lists.sourceforge.net \
    --cc=rich@annexia.org \
    --cc=sacerdot@cs.unibo.it \
    /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