From mboxrd@z Thu Jan 1 00:00:00 1970 Received: (from weis@localhost) by pauillac.inria.fr (8.6.10/8.6.6) id TAA11514 for caml-redistribution; Tue, 29 Aug 1995 19:56:55 +0200 Received: (from weis@localhost) by pauillac.inria.fr (8.6.10/8.6.6) id TAA11490 for caml-list; Tue, 29 Aug 1995 19:55:25 +0200 From: Pierre Weis Message-Id: <199508291755.TAA11490@pauillac.inria.fr> Subject: Constructive criticism To: caml-list@pauillac.inria.fr Date: Tue, 29 Aug 1995 19:55:24 +0200 (MET DST) X-Mailer: ELM [version 2.4 PL21] Content-Type: text Sender: weis I've taken the time to learn caml-light, and I have found it to have been well worth the time. I have a few comments about version 0.7. Positive comments: - I generally like it and intend to use it wherever possible - There are several features I especially like - ability to use pointers when you really really want to - ability to use arrays and strings relatively cleanly - the general operators like "store arbitary type to disk" "make a hash table for type X". - It seems reasonably efficient and correct. - I've looked at many other functional languages and I like caml-light the most. - Thanks for making this available. Constructive criticism (hopefully not just me not noticing something obvious): - The reference manual, under the section "streams, parsers and printers" seems to ignore parsers and printers. They are described elsewhere...it is not a problem, just an annoyance. - The following error seems difficult to understand: #let testit = fun | 4 -> 2 | 1 | 2 -> 3;; Toplevel input: >let testit = fun | 4 -> 2 | 1 | 2 -> 3;; > ^ Syntax error. # Why is this OK with "function" but not with "fun"? It is not possible to match something to the symbol "|" is it? - There seems to be a bug in the string_of_num routine in the contributed libnum package: #let x = num_of_int 1024;; x : num = Int 1024 #let xx = mult_num x x;; xx : num = Int 1048576 #let xxx = mult_num xx x;; xxx : num = Big_int #string_of_num xxx;; - : string = "1737418240" when the result should be "1073741824". - The standard library seems to miss some routines that I would expect / like to see through symmetry (for instance, I would like to have the same functions available for vectors as for lists, whenever such a thing makes sense. Why? Because one would ever use something often enough with lists to justify its inclusion in the core library, then it is probably also useful for vectors, and if they have similar names (such as it_list -> it_vect) one does not have to learn anything new - it extends the functionality of the standard library without making it any harder for a user to rememebr what things do. In particular, it_vect2 could be used to implement a vector dot product as discussed a while ago in the mailing list. Some other routines that I expected that were not present: sprintf ( given so many other printf variants ) copy_string ( given copy_vect ) Other routines that I have needed for my personal standard library that are perhaps of wider use are: let vect_change f v = for i = 0 to (vect_length v) -1 do v.(i) <- f v.(i) done;; An integer modulus, division and gcd that give known answers for negative arguements. let list_of_n n x = list_of_vect (make_vect n x);; let map_list_count f l = let rec work n = function | [] -> [] | h::t -> (f n h)::(work (n+1) t) in work 0 l ;; let map_vect_count f v = vect_of_list (maplistcount f (list_of_vect v));; let rec list_do f = function | [] -> () | h::t -> list_do f t; f h; () ;; let rec extract_list f = function | [] -> [] | h::t -> let r = extract_list f t in if f h then h::r else r ;; let rec create_numlist from upto = if from=upto then [from] else from::(create_numlist (from+1) upto) ;; In particular, map_vect_count is really difficult to implement without going via lists because one needs to initialise the list to something of the appropriate type. Probably futile wish list for implementors with infinite amounts of time. - Packed arrays of enumerated (sum) types with only a small number of possibilities and with no arguements -- like boolean. - I would like to be able to not have to bracket the unary minus before a constant in a function application. eg. let m1 = num_of_int -1;; - I would like to be able to use a symbol twice in pattern matching. For instance, let compare = fun | x x -> 0 | x y -> if x>y then 1 else -1 ;; I realise that this involves (in some cases) a generalised comparison which is not always possible for functions, but a generalised "=" is used elsewhere, and the exception for functional values seems like a reasonable solution. - I would like someway of handling the following nicely: | a b when let (success,res) = big_fn a b in success -> let (success,res) = big_fn a b in res Perhaps something like | a b -> let (success,res) = big_fn a b in if success then res else fail where "fail" would pass one on to the next condition to be tested. - I would like to be able to write functions that are in some way symmetric between parameters. For instance, instead of writing fun | Null x -> x | x Null -> x | x y -> messy_implementation_of_add x y I would like to be able to merge the two first lines into one line. I can't suggest a nice syntax for this that makes sense for more than two parameters and which is still intuitive. This problem is made less of a problem if the next point is done: - In a similar vein to the previous point, it would be nice to be able to have multiple matches have bindings, so the previous example would become: fun | Null x | x Null -> x | x y -> messy_implementation_of_add x y I have a real example with four bindings that all end up executing the same code to the right of an "->" in a given match, and it would have been very nice to be able to not repeat it four times, and there are enough elements in the binding to make a function call messy. - I would like to be able to define a new structure instance with a declaration like { x ; Field3=5 ; Field7 = 9 } which would make a copy of the structure x, whilst changing the two given fields to the appropriate values. Why? So I can write a program that has lots of things that it will eventually do with slight changes to a structure, and I don't have to go through and change routines that are irrelevant to the change. Really grasping at straws: - I would like to be able to perform "function overloading" as in C++. Furthurmore, greedy person that I am, I would like this overloaded-ability to automagically be passed through into functions that use the overloaded function (which I realise is very difficult, and would either require multiple object code for each possible operator combination, or an extra, "invisible" function parameter to be passed to the function when the type resolution is finally done.) I realise that this is especially difficult in a multiple module context, and that assigning a type to such a function would be difficult, but I still mention it as I would really like it. Maybe I should go to caml rather than caml-light. Andrew Conway arc@labri.u-bordeaux.fr