Version française
Home     About     Download     Resources     Contact us    
Browse thread
Constructive criticism
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: Pierre Weis <weis@p...>
Subject: Constructive criticism
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 <abstr>
             #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