* [Caml-list] Are map and iter guaranteed to be called in forwards order? @ 2004-08-17 12:00 Richard Jones 2004-08-17 12:45 ` Damien Doligez 2004-08-17 14:26 ` John Prevost 0 siblings, 2 replies; 10+ messages in thread From: Richard Jones @ 2004-08-17 12:00 UTC (permalink / raw) To: caml-list Are the map and iter[1] functions guaranteed to be called in the expected order? In other words will this always produce the same result: # let i = ref 0 ;; val i : int ref = {contents = 0} # let xs = List.map (fun _ -> incr i; !i) [ 1;1;1;1;1;1;1;1 ];; val xs : int list = [1; 2; 3; 4; 5; 6; 7; 8] Rich. [1] From List, for example, but could equally apply to the other library modules. -- Richard Jones. http://www.annexia.org/ http://www.j-london.com/ Merjis Ltd. http://www.merjis.com/ - improving website return on investment NET::FTPSERVER is a full-featured, secure, configurable, database-backed FTP server written in Perl: http://www.annexia.org/freeware/netftpserver/ ------------------- 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] 10+ messages in thread
* Re: [Caml-list] Are map and iter guaranteed to be called in forwards order? 2004-08-17 12:00 [Caml-list] Are map and iter guaranteed to be called in forwards order? Richard Jones @ 2004-08-17 12:45 ` Damien Doligez 2004-08-17 14:26 ` John Prevost 1 sibling, 0 replies; 10+ messages in thread From: Damien Doligez @ 2004-08-17 12:45 UTC (permalink / raw) To: caml Caml On Aug 17, 2004, at 14:00, Richard Jones wrote: > Are the map and iter[1] functions guaranteed to be called in the > expected order? iter: yes map: no -- Damien ------------------- 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] 10+ messages in thread
* Re: [Caml-list] Are map and iter guaranteed to be called in forwards order? 2004-08-17 12:00 [Caml-list] Are map and iter guaranteed to be called in forwards order? Richard Jones 2004-08-17 12:45 ` Damien Doligez @ 2004-08-17 14:26 ` John Prevost 2004-08-17 14:56 ` Richard Jones 2004-08-18 0:57 ` Jon Harrop 1 sibling, 2 replies; 10+ messages in thread From: John Prevost @ 2004-08-17 14:26 UTC (permalink / raw) To: Caml Mailing List On Tue, 17 Aug 2004 13:00:53 +0100, Richard Jones <rich@annexia.org> wrote: > Are the map and iter[1] functions guaranteed to be called in the > expected order? In other words will this always produce the same > result: {...} > [1] From List, for example, but could equally apply to the other > library modules. You should also note that both map and iter can sensibly be provided for data structures that don't have any strong guarantee of order at all. For example, a set. As a rule of thumb, I'd say it's best not to depend on order in these calls unless (perhaps) you have implemented the routine yourself, or are using a library that specifically says what order the calls will be processed. As Damien says, the documentation for List.map makes no guarantee of order, while List.iter's documentation says that it is identical to another construct that does guarantee order. John. ------------------- 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] 10+ messages in thread
* Re: [Caml-list] Are map and iter guaranteed to be called in forwards order? 2004-08-17 14:26 ` John Prevost @ 2004-08-17 14:56 ` Richard Jones 2004-08-17 15:13 ` Anil Madhavapeddy ` (2 more replies) 2004-08-18 0:57 ` Jon Harrop 1 sibling, 3 replies; 10+ messages in thread From: Richard Jones @ 2004-08-17 14:56 UTC (permalink / raw) Cc: Caml Mailing List This came up because I wanted a sensible way to number a list of items. The obvious imperative approach is: # let items = ['a';'c';'e';'g';'i'];; val items : char list = ['a'; 'c'; 'e'; 'g'; 'i'] # let i = ref 0;; val i : int ref = {contents = 0} # let items = List.map (fun item -> let n = !i in incr i; n, item) items;; val items : (int * char) list = [(0, 'a'); (1, 'c'); (2, 'e'); (3, 'g'); (4, 'i')] The functional approach is comparatively long-winded: you have to effectively write your own loop explicitly, and the obvious way to write it isn't tail recursive, so you have to do it with accumulators. It'd be nicer to have a library HOF to do this. Rich. -- Richard Jones. http://www.annexia.org/ http://www.j-london.com/ Merjis Ltd. http://www.merjis.com/ - improving website return on investment MOD_CAML lets you run type-safe Objective CAML programs inside the Apache webserver. http://www.merjis.com/developers/mod_caml/ ------------------- 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] 10+ messages in thread
* Re: [Caml-list] Are map and iter guaranteed to be called in forwards order? 2004-08-17 14:56 ` Richard Jones @ 2004-08-17 15:13 ` Anil Madhavapeddy 2004-08-17 15:17 ` Jean-Marie Gaillourdert 2004-08-17 15:19 ` John Prevost 2 siblings, 0 replies; 10+ messages in thread From: Anil Madhavapeddy @ 2004-08-17 15:13 UTC (permalink / raw) To: Richard Jones; +Cc: Caml Mailing List On Tue, Aug 17, 2004 at 03:56:53PM +0100, Richard Jones wrote: > This came up because I wanted a sensible way to number a list of > items. The obvious imperative approach is: > > # let items = ['a';'c';'e';'g';'i'];; > val items : char list = ['a'; 'c'; 'e'; 'g'; 'i'] > # let i = ref 0;; > val i : int ref = {contents = 0} > # let items = List.map (fun item -> let n = !i in incr i; n, item) items;; > val items : (int * char) list = > [(0, 'a'); (1, 'c'); (2, 'e'); (3, 'g'); (4, 'i')] > > The functional approach is comparatively long-winded: you have to > effectively write your own loop explicitly, and the obvious way to > write it isn't tail recursive, so you have to do it with accumulators. > Would List.combine come in handy? Something like: # let rec numlist n a = match n with |0 -> a |x -> numlist (n-1) (x::a);; val numlist : int -> int list -> int list = <fun> # let number l = List.combine (numlist (List.length l) []) l;; val number : 'a list -> (int * 'a) list = <fun> # let items = ['a';'c';'e';'g';'i'];; val items : char list = ['a'; 'c'; 'e'; 'g'; 'i'] # number items;; - : (int * char) list = [(1, 'a'); (2, 'c'); (3, 'e'); (4, 'g'); (5, 'i')] -- Anil Madhavapeddy http://anil.recoil.org University of Cambridge http://www.cl.cam.ac.uk ------------------- 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] 10+ messages in thread
* Re: [Caml-list] Are map and iter guaranteed to be called in forwards order? 2004-08-17 14:56 ` Richard Jones 2004-08-17 15:13 ` Anil Madhavapeddy @ 2004-08-17 15:17 ` Jean-Marie Gaillourdert 2004-08-17 15:19 ` John Prevost 2 siblings, 0 replies; 10+ messages in thread From: Jean-Marie Gaillourdert @ 2004-08-17 15:17 UTC (permalink / raw) To: caml-list Hi, Am Dienstag, 17. August 2004 16:56 schrieb Richard Jones: > This came up because I wanted a sensible way to number a list of > items. The obvious imperative approach is: > > # let items = ['a';'c';'e';'g';'i'];; > val items : char list = ['a'; 'c'; 'e'; 'g'; 'i'] > # let i = ref 0;; > val i : int ref = {contents = 0} > # let items = List.map (fun item -> let n = !i in incr i; n, item) > items;; val items : (int * char) list = > [(0, 'a'); (1, 'c'); (2, 'e'); (3, 'g'); (4, 'i')] > > The functional approach is comparatively long-winded: you have to > effectively write your own loop explicitly, and the obvious way to > write it isn't tail recursive, so you have to do it with accumulators. > > It'd be nicer to have a library HOF to do this. There is a higher order function to do this: fold List.rev (List.fold_left (fun xs x -> match xs with [] -> [(0,x)] | (i,_)::_ -> (i+1,x)::xs) [] items);; Regards, Jean-Marie ------------------- 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] 10+ messages in thread
* Re: [Caml-list] Are map and iter guaranteed to be called in forwards order? 2004-08-17 14:56 ` Richard Jones 2004-08-17 15:13 ` Anil Madhavapeddy 2004-08-17 15:17 ` Jean-Marie Gaillourdert @ 2004-08-17 15:19 ` John Prevost 2 siblings, 0 replies; 10+ messages in thread From: John Prevost @ 2004-08-17 15:19 UTC (permalink / raw) To: Richard Jones; +Cc: Caml Mailing List On Tue, 17 Aug 2004 15:56:53 +0100, Richard Jones <rich@annexia.org> wrote: > This came up because I wanted a sensible way to number a list of > items. The obvious imperative approach is: > > # let items = ['a';'c';'e';'g';'i'];; > val items : char list = ['a'; 'c'; 'e'; 'g'; 'i'] > # let i = ref 0;; > val i : int ref = {contents = 0} > # let items = List.map (fun item -> let n = !i in incr i; n, item) items;; > val items : (int * char) list = > [(0, 'a'); (1, 'c'); (2, 'e'); (3, 'g'); (4, 'i')] > > The functional approach is comparatively long-winded: you have to > effectively write your own loop explicitly, and the obvious way to > write it isn't tail recursive, so you have to do it with accumulators. > > It'd be nicer to have a library HOF to do this. How about fold? let number l = let _, l = List.fold_left (fun (n, l) i -> (n+1, (n, i)::l)) (0, []) l in List.rev l You could even do fold with side effects if you really want to: let number' l = let i = ref 0 in let l = List.fold_left (fun l x -> let n = !i in incr i; (n, x) :: l) [] l in List.rev l Or define your own version of map, that you have explicitly written to be based on fold_left, which allows you to be sure that it will always work the same way: let folding_map f l = let l = List.fold_left (fun l x -> (f x)::l) [] l in List.rev l John. ------------------- 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] 10+ messages in thread
* Re: [Caml-list] Are map and iter guaranteed to be called in forwards order? 2004-08-17 14:26 ` John Prevost 2004-08-17 14:56 ` Richard Jones @ 2004-08-18 0:57 ` Jon Harrop 2004-08-18 5:11 ` skaller 1 sibling, 1 reply; 10+ messages in thread From: Jon Harrop @ 2004-08-18 0:57 UTC (permalink / raw) To: caml-list On Tuesday 17 August 2004 15:26, John Prevost wrote: > You should also note that both map and iter can sensibly be provided > for data structures that don't have any strong guarantee of order at > all. For example, a set... That is so nineties. Someone at INRIA kindly changed this of late (3.08) - The set and map data structures do now guarantee element order. On Tuesday 17 August 2004 16:13, Anil Madhavapeddy wrote: > # let rec numlist n a = match n with |0 -> a |x -> numlist (n-1) (x::a);; > val numlist : int -> int list -> int list = <fun> > ... This would work but I think we can do better. Deforesting is a good start - we don't want lots of big data structures cluttering up the place... On Tuesday 17 August 2004 16:17, Jean-Marie Gaillourdert wrote: > List.rev > (List.fold_left (fun xs x -> > match xs with > [] -> [(0,x)] > | (i,_)::_ -> (i+1,x)::xs) [] items);; That's good, but it's no hot potato. Using fold is a great idea, IMHO. The List.fold_left function is preferable to List.fold_right because the former is tail-recursive and, therefore, will be much faster for big lists. But we can do more to get rid of the pattern matching - we can fold over a 2-tuple which accumulates the current index and the current list (in reverse order): On Tuesday 17 August 2004 16:19, John Prevost wrote: > let number l = > let _, l = List.fold_left (fun (n, l) i -> (n+1, (n, i)::l)) (0, []) l in > List.rev l > ... Almost there, me thinks. You can tweak this one by using the "snd" function to rip out the second half of the 2-tuple, rather than using pattern matching, squeezing the whole function into a slender pair of lines: let index l = List.rev (snd (List.fold_left (fun (i, l) e -> i+1, (i, e)::l) (0, []) l));; If you're feeling really adventurous, you can factor the algorithm agressively (grrr!), producing many useful functions at intermediate stages. Essentially, we've been folding over one data structure, handling the index and the element, and inserting into another data structure given a value representing the empty data structure. We could productively generalise this to a function with an outrageous type: # let generic_mapi fold insert empty t = snd (fold (fun (i, l) e -> i+1, insert (i, e) l) (0, empty) t);; val generic_mapi : ((int * 'a -> 'b -> int * 'c) -> int * 'd -> 'e -> 'f * 'g) -> (int * 'b -> 'a -> 'c) -> 'd -> 'e -> 'g = <fun> First, let us use the generic_mapi function to create a HOF list_rev_mapi which does a List.rev_map of a given function applied to the index as well as the value of each element in the given list: # let list_rev_mapi f l = (generic_mapi List.fold_left (fun (i, e) t -> f i e :: t) [] l);; val list_rev_mapi : (int -> 'a -> 'b) -> 'a list -> 'b list = <fun> This function can then be used to create your function to convert a list into an indexed list by passing a function which creates an index-value 2-tuple to our list_rev_mapi HOF and reversing its result: # let ilist_of_list l = List.rev (list_rev_mapi (fun i e -> i, e) l);; val ilist_of_list : 'a list -> (int * 'a) list = <fun> # ilist_of_list ['a'; 'c'; 'e'; 'g'; 'i'];; - : (int * char) list = [(0, 'a'); (1, 'c'); (2, 'e'); (3, 'g'); (4, 'i')] The following, nifty HOF converts left fold types into right fold types and vice versa: # let rev_fold fold f a b = fold (fun a b -> f b a) b a;; val rev_fold : (('a -> 'b -> 'c) -> 'd -> 'e -> 'f) -> ('b -> 'a -> 'c) -> 'e -> 'd -> 'f = <fun> This rev_fold function can be used with our (stupendously generic) generic_mapi function to index the elements of a set of chars, placing the result in a hash table mapping chars to indices: # module CharKey = struct type t=char let compare = compare end;; module CharKey : sig type t = char val compare : 'a -> 'a -> int end # module CharSet = Set.Make(CharKey);; ... # let piece_of_cake s = let h = Hashtbl.create (CharSet.cardinal s) in let fold = rev_fold CharSet.fold in generic_mapi fold (fun (i, e) () -> Hashtbl.add h e i) () s; h;; val piece_of_cake : CharSet.t -> (CharSet.elt, int) Hashtbl.t = <fun> For example: # let set_of s = let set = ref CharSet.empty in String.iter (fun c -> set := CharSet.add c !set) s; !set;; val set_of : string -> CharSet.t = <fun> # let test_set = set_of "The wagged wascle wan wound the wugged wock";; val test_set : CharSet.t = <abstr> # let test_table = piece_of_cake test_set;; val test_table : (CharSet.elt, int) Hashtbl.t = <abstr> # Hashtbl.find test_table 'g';; - : int = 9 So thirteen characters in the ASCII alphabet came after 'a' in our string. Ha! Try writing that in Felix (in another mailing-list, of course ;-). Cheers, Jon. ------------------- 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] 10+ messages in thread
* Re: [Caml-list] Are map and iter guaranteed to be called in forwards order? 2004-08-18 0:57 ` Jon Harrop @ 2004-08-18 5:11 ` skaller 2004-08-18 7:10 ` skaller 0 siblings, 1 reply; 10+ messages in thread From: skaller @ 2004-08-18 5:11 UTC (permalink / raw) To: Jon Harrop; +Cc: caml-list On Wed, 2004-08-18 at 10:57, Jon Harrop wrote: > On Tuesday 17 August 2004 15:26, John Prevost wrote: > let index l = > List.rev (snd (List.fold_left (fun (i, l) e -> i+1, (i, e)::l) (0, []) l));; > Ha! Try writing that in Felix (in another mailing-list, of course ;-). Unfair to make that challange and deny the right to a response :) So you get it: its much the same as the Caml version except the type annotations on the arguments are mandatory in Felix: fun index[t] (l:list[t]) => rev (snd ( fold_left (fun (i:int, l: list [t], e: int * t) => i+1, Cons ((i, e),l) ) (0, Empty[t]) l )) ; The actual code above doesn't compile due to a bug, so I'm glad of the example -- thanks! [Looks like I forgot to alpha convert before unifying during overload resolution] However its *should* work: What Caml can do and Felix cannot, is pass a *polymorphic* function as an argument. Caml allows that -- but then you can only use it monomorphically [unless you wrap it in a record]. -- John Skaller, mailto:skaller@users.sf.net voice: 061-2-9660-0850, snail: PO BOX 401 Glebe NSW 2037 Australia Checkout the Felix programming language http://felix.sf.net ------------------- 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] 10+ messages in thread
* Re: [Caml-list] Are map and iter guaranteed to be called in forwards order? 2004-08-18 5:11 ` skaller @ 2004-08-18 7:10 ` skaller 0 siblings, 0 replies; 10+ messages in thread From: skaller @ 2004-08-18 7:10 UTC (permalink / raw) To: Jon Harrop; +Cc: caml-list On Wed, 2004-08-18 at 15:11, skaller wrote: > On Wed, 2004-08-18 at 10:57, Jon Harrop wrote: > > On Tuesday 17 August 2004 15:26, John Prevost wrote: > > > let index l = > > List.rev (snd (List.fold_left (fun (i, l) e -> i+1, (i, e)::l) (0, []) l));; > > > Ha! Try writing that in Felix (in another mailing-list, of course ;-). > > The actual code above doesn't compile due to a bug, Oops. Its a bug in my translation of the routine, not in Felix! The code below actually works. Clear advantages of Ocaml here are: (a) Ocaml's type inference simplifies presentation (b) :: as both constructor and pattern in Ocaml are nice, as is [x;y;z] list constructor (Felix uses :: like C++ for qualification :( (c) Felix anonymous functions only accept one argument (needs fixing) (d) Felix function parameters aren't general patterns: at best a single top level tuple match is allowed (ugly constraint) However the worst problem isn't shown by the correct code: whilst Ocaml's error messages are sometimes confusing as to reason and location, and Felix is generally better at locating the source of a problem -- Felix sometimes gives very confusing explanations -- it took me an hour to finally convince myself I actually had a type error in my previous code, rather than a compiler bug. The fact that an ordinary programmer can write a compiler for a powerful language in Ocaml really shows just how good Ocaml is :) --------------------------------- include "std"; open List; fun snd(x,y)=>y; fun fst(x,y)=>x; fun index[t] (l:list[t]) = { typedef il_t = int * list [int * t]; fun f(il:il_t) (e: t) => match il with | ?i,?l => i+1, Cons ((i, e),l) endmatch ; return rev (snd ( fold_left f of (il_t) (0, Empty[int * t]) l )) ; } var x = Empty[int]; x = Cons(11,x); x = Cons(22,x); x = Cons(33,x); x = Cons(44,x); x = Cons(55,x); x = Cons(66,x); val z = index x; iter (proc (x:int,y:int) { print x; print " -> "; print y; endl; } ) z ; ------------ [skaller@pelican] ~/links/flx>bin/flx -Ilib --force il 0 -> 66 1 -> 55 2 -> 44 3 -> 33 4 -> 22 5 -> 11 -- John Skaller, mailto:skaller@users.sf.net voice: 061-2-9660-0850, snail: PO BOX 401 Glebe NSW 2037 Australia Checkout the Felix programming language http://felix.sf.net ------------------- 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] 10+ messages in thread
end of thread, other threads:[~2004-08-18 7:10 UTC | newest] Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2004-08-17 12:00 [Caml-list] Are map and iter guaranteed to be called in forwards order? Richard Jones 2004-08-17 12:45 ` Damien Doligez 2004-08-17 14:26 ` John Prevost 2004-08-17 14:56 ` Richard Jones 2004-08-17 15:13 ` Anil Madhavapeddy 2004-08-17 15:17 ` Jean-Marie Gaillourdert 2004-08-17 15:19 ` John Prevost 2004-08-18 0:57 ` Jon Harrop 2004-08-18 5:11 ` skaller 2004-08-18 7:10 ` skaller
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox