caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [Caml-list] Re: [Ocaml-lib-devel] pMap.ml
       [not found]     ` <008901c38bfd$aa08b530$6f01a8c0@PWARP>
@ 2003-10-06 11:54       ` Richard Jones
  2003-10-06 12:06         ` Stefano Zacchiroli
       [not found]         ` <20031006114114.GA12034@roke.freak>
  0 siblings, 2 replies; 5+ messages in thread
From: Richard Jones @ 2003-10-06 11:54 UTC (permalink / raw)
  To: ocaml-lib-devel; +Cc: caml-list

Nicolas Cannasse wrote:
> Markus Mottl wrote:
> > I wrote:
> > > Yikes. The good thing about the previous code was it _wasn't_ purely
> > > functional.
> > >
> > > I'll never understand this fear of mutability.
> >
> > I have no fear of mutability. It's just that there was absolutely
> > no apparent advantage of having mutability in this datastructure,
> > neither performance- nor expressiveness-wise. A reference holding this
> > datastructure outside of the library would do as well. You are not afraid
> > of dereferencing values, are you? ;-)
> 
> 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.

While I'm certainly not an experienced OCaml programmer like Markus
and Nicolas, I have to come down on the Nicolas's side here.

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:

let hash = {| "foo", "bar"; "a", "b" |} in
hash.{"foo"} <- "baz";
prerr_endline hash.{"foo"};	# would print "baz"

While we're about it, Hashtbl.keys and Hashtbl.values functions would
be really useful in the standard library. They are defined simply as:

let keys = Hashtbl.fold (fun key _ xs -> key :: xs);;
let values = Hashtbl.fold (fun _ value xs -> value :: xs);;

Rich.

-- 
Richard Jones. http://www.annexia.org/ http://freshmeat.net/users/rwmj
Merjis Ltd. http://www.merjis.com/ - all your business data are belong to you.
"One serious obstacle to the adoption of good programming languages is
the notion that everything has to be sacrificed for speed. In computer
languages as in life, speed kills." -- Mike Vanier

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Caml-list] Re: [Ocaml-lib-devel] pMap.ml
  2003-10-06 11:54       ` [Caml-list] Re: [Ocaml-lib-devel] pMap.ml Richard Jones
@ 2003-10-06 12:06         ` Stefano Zacchiroli
  2003-10-07 16:37           ` brogoff
       [not found]         ` <20031006114114.GA12034@roke.freak>
  1 sibling, 1 reply; 5+ messages in thread
From: Stefano Zacchiroli @ 2003-10-06 12:06 UTC (permalink / raw)
  To: caml-list

On Mon, Oct 06, 2003 at 12:54:03PM +0100, 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:
> 
> let hash = {| "foo", "bar"; "a", "b" |} in
> hash.{"foo"} <- "baz";
> prerr_endline hash.{"foo"};	# would print "baz"

  http://camlcvs.inria.fr/cgi-bin/osearch?conf=humps&words=hashtbl

with a slight different syntax:

  let hash = {}["foo", "bar"; "a", "b"] in
  hash{"foo"} <- "baz";
  prerr_endline (hash{"foo"})

Cheers.

-- 
Stefano Zacchiroli  --  Master in Computer Science @ Uni. Bologna, Italy
zack@{cs.unibo.it,debian.org,bononia.it}  -  http://www.bononia.it/zack/
"  I know you believe you understood what you think I said, but I am not
sure you realize that what you heard is not what I meant!  " -- G.Romney

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [Caml-list] Re: [Ocaml-lib-devel] pMap.ml
       [not found]           ` <20031006125246.GA25703@cs.unibo.it>
@ 2003-10-06 16:56             ` Markus Mottl
  0 siblings, 0 replies; 5+ messages in thread
From: Markus Mottl @ 2003-10-06 16:56 UTC (permalink / raw)
  To: Michal Moskal, Richard Jones, Claudio Sacerdoti Coen
  Cc: ocaml-lib-devel, caml-list

[-- 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

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Caml-list] Re: [Ocaml-lib-devel] pMap.ml
  2003-10-06 12:06         ` Stefano Zacchiroli
@ 2003-10-07 16:37           ` brogoff
  2003-10-07 20:16             ` skaller
  0 siblings, 1 reply; 5+ messages in thread
From: brogoff @ 2003-10-07 16:37 UTC (permalink / raw)
  To: caml-list

While it's nice to have stopgap solutions to these "problems", IMO the right
solution will be possible when we have some kind of overloading in the language.
Rather than having lots of squirrelly notations for hashtable access (and string
access, and BigArray access, and...) we should just be able to index like arrays
and be done with it. Lack of user defined overloading has always been a weak
point in the entire ML family of languages, IMO.

Hopefully, now that 3.07 is out, work on GCaml proceeds apace...

-- Brian

On Mon, 6 Oct 2003, Stefano Zacchiroli wrote:
> On Mon, Oct 06, 2003 at 12:54:03PM +0100, 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:
> >
> > let hash = {| "foo", "bar"; "a", "b" |} in
> > hash.{"foo"} <- "baz";
> > prerr_endline hash.{"foo"};	# would print "baz"
>
>   http://camlcvs.inria.fr/cgi-bin/osearch?conf=humps&words=hashtbl
>
> with a slight different syntax:
>
>   let hash = {}["foo", "bar"; "a", "b"] in
>   hash{"foo"} <- "baz";
>   prerr_endline (hash{"foo"})
>
> Cheers.
>
> --
> Stefano Zacchiroli  --  Master in Computer Science @ Uni. Bologna, Italy
> zack@{cs.unibo.it,debian.org,bononia.it}  -  http://www.bononia.it/zack/
> "  I know you believe you understood what you think I said, but I am not
> sure you realize that what you heard is not what I meant!  " -- G.Romney
>
> -------------------
> To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
> Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
>

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Caml-list] Re: [Ocaml-lib-devel] pMap.ml
  2003-10-07 16:37           ` brogoff
@ 2003-10-07 20:16             ` skaller
  0 siblings, 0 replies; 5+ messages in thread
From: skaller @ 2003-10-07 20:16 UTC (permalink / raw)
  To: brogoff; +Cc: caml-list

On Wed, 2003-10-08 at 02:37, brogoff@speakeasy.net wrote:
> While it's nice to have stopgap solutions to these "problems", IMO the right
> solution will be possible when we have some kind of overloading in the language.
> Rather than having lots of squirrelly notations for hashtable access (and string
> access, and BigArray access, and...) we should just be able to index like arrays
> and be done with it. Lack of user defined overloading has always been a weak
> point in the entire ML family of languages, IMO.
> 

Felix has overloading. My feelings: lack of overloading
has two advantages.

(1) definiteness

Its definite what you're refering to: the lookup rules
are simple. Unlike overloading systems such as the lookup
and overload resolution in C++.

(2) prevents newbie abuse

Well, I have seen so much *horrendous* C++ garbage
where people thought overloading was clever.

I have also seen bad consequences where more expert
people constructed a badly designed mess -- such as the
C++ iostream facility. They got confused, and tried
to 'overload' cout << x for x being a 'character'. Only,
when iostreams got templated (character type became a type parameter)
it no longer made so much sense .. 

Yes, I miss overloading in Ocaml. But not all that much :-)


-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2003-10-07 20:18 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [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       ` [Caml-list] Re: [Ocaml-lib-devel] pMap.ml 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 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).