caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* Constructive criticism
@ 1995-08-29 17:55 Pierre Weis
  1995-08-29 18:08 ` Pierre Weis
  1995-08-30 13:34 ` Xavier Leroy
  0 siblings, 2 replies; 4+ messages in thread
From: Pierre Weis @ 1995-08-29 17:55 UTC (permalink / raw)
  To: caml-list

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




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

* Re: Constructive criticism
  1995-08-29 17:55 Constructive criticism Pierre Weis
@ 1995-08-29 18:08 ` Pierre Weis
  1995-08-30 13:07   ` Andrew Conway
  1995-08-30 13:34 ` Xavier Leroy
  1 sibling, 1 reply; 4+ messages in thread
From: Pierre Weis @ 1995-08-29 18:08 UTC (permalink / raw)
  To: Pierre Weis

Thank you very much for the bugs report, we'll correct them as soon as
possible.

It's a pleasure to answer to your numerous and so constructive suggestions:

Patterns in fun matches:
------------------------
>        - 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?      

The rule of thumb is that complex patterns have to be bracketed when
used inside ``fun'' pattern matchings. And since ``or'' patterns, that
is patterns separated by the or symbol ``|'', are not considered basic.

Technically, this strange treatment of patterns is mainly due to Yacc
restrictions, and partly due to real syntactic ambiguities, since fun
patterns may bind several parameters (when function patterns only bind
one). Consider the pattern ``C D'', where C and D are constructors.
This patterns is syntactically ambiguous: is it the application of
constructor C to constructor D, or two successive parameters,
parameter C followed by parameter D ? In a function pattern the first
interpretation is used, in a fun pattern the second one is assumed
(hence, when you need the first meaning in a fun pattern you must
bracket the application of constructor C to D, writing (C D)).

Library considerations:
-----------------------
>        - The standard library seems to miss some routines that
>          I would expect / like to see through symmetry

Yes, the Caml Light library has been designed to be as light as possible!
Some one-liner functions have been omitted (such as your copy_string,
which is just (function s -> s ^ "")). Some other useful functions
may not be provided in the standard library (for instance sprintf is
only available via the contrib/libstr library, as the function str__format).

In contrast, the Caml V3.1 library has more functions. Almost all the
functions you suggest to add to the standard libray have a counterpart
in this library, some time a  bit more general than yours. I give the
Caml V3.1 version when it is better than yours:

> let list_of_n n x = list_of_vect (make_vect n x);;

Your list_of_n function is not optimal, since you allocate a vector
that you immediately throw away to get the list of its elements. It it
more efficent to create the list directly.

Anyway, list_of_n is usually named replicate in Caml:

let rec replicate n x =
 if n <= 0 then [] else x :: replicate (n - 1) 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;;

Your map_list_count function is a special case of the more general
map_i functional defined as:

let map_i f =
 let rec map_i_rec i = function
     [] -> [] | x::l -> f i x::map_i_rec (i+1) l in
 map_i_rec;;
map_i : (int -> 'a -> 'b) -> int -> 'a list -> 'b list = <fun>

The corresponding primitive for vectors is map_i_vect_list to return a list:

let map_i_vect_list f i0 v =
 let rec map_i_rec n =
  if n >= vect_length v then [] else f n v.(n)::map_i_rec (succ n) in
 map_i_rec i0;;
map_i_vect_list : (int -> 'a -> 'b) -> int -> 'a vect -> 'b list = <fun>

or map_i_vect to return a new vector:

let map_i_vect f i0 v =
  let len = vect_length v - i0 in
  if len <= 0 then [| |] else
  let result = make_vect len (f i0 v.(i0)) in
  for i = i0 + 1 to i0 + len - 1 do result.(i - i0) <- f i v.(i) done;
  result;;
map_i_vect : (int -> 'a -> 'b) -> int -> 'a vect -> 'b vect = <fun>

>              let rec list_do f = function
Your list_do that applies a function to the ellements of a list in
reverse order is usually called rev_do_list:
              let rec rev_do_list f = function
                | [] -> ()
                | h::t -> rev_do_list f t; f h; ();;

extract_list is known as filter in Caml V3.1.

create_numlist corresponds to interval:
(* Lists of consecutive integers *)
let interval n m =
 let rec interval_n (l,m) =
  if n > m then l else interval_n (m::l,pred m) in
 interval_n ([],m);;

let range = interval 1;;

Packed arrays:
--------------

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

Why do you want them packed ? You can use vectors. I agree that in
some cases vectors waste memory locations, in particular for caracters
(but Caml provides strings).
In some cases, you can consider to use bit_vectors (I can send you such a
library if you want), otherwise you can use integers and logical
shift operations as in C, but this is very low-level. The best
solution is probably to consider these packed arrays as a compiler
optimisation, but is it worth the work it needs ?

Unary minus:
------------
>        - 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;;

Well, I presume that you want to use the same symbol for unary and
binary minus (that is the mathematical ``-''). In this case you may be
able to distinguish between those two. If you denote function
application by mere juxtaposition, then f - 1 can either be the
application of function f to the number -1 or the subtraction of 1 to
the integer variable f. You may want to distinguish with spaces: then
-1 is a single token and f -1 is an application, while f - 1 is a
binary operation. The problem is that now f-1 is an application, and
thus x*y-1 is understood as x * (y (-1)). This is strange. An
admissible solution could be to give the same treatment to other
binary operators...

Extended pattern matching:
--------------------------

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

You can encode this using a guard (a ``when'' side-condition) in your
pattern matching clause:
let compare = function
  | (x, y) when x = y -> 0
  | (x, y) -> if x > y then 1 else -1;;
compare : 'a * 'a -> int = <fun>

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

You're right. It is conceivable to add this kind of ``non-linear''
patterns to Caml: the compiler just has to generate the right ``when''
conditions. This may be done some day. This was not done to maintain a
good property of Caml pattern matching: pattern matching selection
is fast, and in particular it cannot loop for ever. In the presence of
cyclic data, the equality test generated by non linear patterns may
need an unpredictable amount of computation to complete, or may even
loop for ever.

In fact we prefered to implement guards rather non linear patterns,
since guards are more general, allowing to test not only variable
equalities but arbitrary boolean conditions (in particular they allow
user defined equality rather than the built-in ad hoc equality).

Continue in patterns:
---------------------

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

This is known as the ``continue in pattern matching'' feature in the
Caml community. It has been implemented in Caml V3.1 some time ago.
You simply use ``continue'' instead of your ``fail'', and the semantic
is exactly what you wanted.

In fact, a generalised version is implemented: continue statements may
refer to a specific pattern matching, which is useful in case of
nested pattern matching.

Thus your example is written as:

let big_fn a b = if a then (a, b + 1) else (false, b);;
Value big_fn is <fun> : 'a * int -> 'a * int

let g = function continuing g
 | (a,b) -> let (success,res) = big_fn (a, b) in
    if success then res else continue g
 | _ -> 2;;
Value g is <fun> : bool * int -> int

#g (true, 4);;
5 : int

#g (false, 4);;
2 : int

In some cases, you can simulate the continue statement with some
rewritting of your function and a ``try raise'' construct. Something like:

let g x = try continuing_g x with continue -> rest_of_patterns x

let continuing_g = function
 | (a,b) -> let (success,res) = big_fn (a, b) in
    if success then res else raise continue
 | z -> rest_of_patterns z

and rest_of_patterns _ = 2

This trick is not a solution: it is untractable for complex pattern matching.

Generalized orpats:
-------------------
>        - 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: 

Your problem is just to generalize ``or'' patterns, to allow them to
bind variables. Once more this is possible in Caml V3.1.

Given:

type nat = Null | Succ of nat;;

let messy_implementation_of_add x y = Null;;

You may use ``or'' patterns that bind variables to write:

let f = function
  | Null, x | x, Null -> x
  | x, y -> messy_implementation_of_add x y;;
Value f is <fun> : nat * nat -> nat

#f (Null, Succ Null);;
(Succ Null) : nat

#f (Succ Null, Null);;
(Succ Null) : nat

#f (Succ Null, Succ Null);;
Null : nat

Definitions of record values:
-----------------------------

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

This a well known problem: allocation of record values is much more
messy than allocation of sum type values. As you mentioned, this is
particularly evident when you have to modify a few part of a given
record.

However, in Caml you get the capability to treat the fields that have to be
modified in an imperative way: you just declare those fields ``mutable''
when defining the record type. This way you share the record and its
modified version, and just have to change what have to be modified.
Your example would be something like:
r -> r.Field3 <- 5; r.Field7 <- 9; r

Unfortunately, when you need a new (fresh) data structure, this
solution does not work.
Some partial solutions have been proposed: for instance Caml V3.1 provides a
short-hand to define the content of a record field: when no expression
is associated to a field name then a variable expression equal to the
field name is assumed.
This way { x; y} is read as {x = x; y = y}. Your example is then a bit
simplified 
{ Field1; Field2; Field3; Field4; Field5; Field6; Field7 } ->
{ Field1; Field2; Field3 = 5 ; Field4; Field5; Field6; Field7 = 9 }

Unfortunately, this does not solve your maintenance problem.
By contrast, your generalised ellipse is an exiting alternative, since
it allows an easy modification of allocating routines.

Overloading:
------------
>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 ...

This is really difficult to provide, and is a long-time research problem.
However, there exists a restricted form of overloading in Caml V3.1
that we called ``static overloading''.

We recently made progress on that point and proposed new type systems
and new compilation schemes to provide a general overloading facility
(see the article ``Extensional Polymorphism'' in POPL 95).
This work still has to be fully incorporated into a working Caml system.

>Maybe I should go to caml rather than
>          caml-light.
Use both!

Pierre Weis
----------------------------------------------------------------------------
WWW Home Page: http://pauillac.inria.fr/~weis
Projet Cristal
INRIA, BP 105, F-78153 Le Chesnay Cedex (France)
E-mail: Pierre.Weis@inria.fr
Telephone: +33 1 39 63 55 98
Fax: +33 1 39 63 53 30
----------------------------------------------------------------------------




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

* Re: Constructive criticism
  1995-08-29 18:08 ` Pierre Weis
@ 1995-08-30 13:07   ` Andrew Conway
  0 siblings, 0 replies; 4+ messages in thread
From: Andrew Conway @ 1995-08-30 13:07 UTC (permalink / raw)
  To: Pierre Weis


>Thank you very much for the bugs report, we'll correct them as soon as
>possible.
>
>It's a pleasure to answer to your numerous and so constructive suggestions:

Thank you for your very extensive answers. 

>Patterns in fun matches:
>------------------------
>>        - 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?      
>
>The rule of thumb is that complex patterns have to be bracketed when
>used inside ``fun'' pattern matchings. And since ``or'' patterns, that
>is patterns separated by the or symbol ``|'', are not considered basic.
>
>Technically, this strange treatment of patterns is mainly due to Yacc
>restrictions, and partly due to real syntactic ambiguities, since fun
>patterns may bind several parameters (when function patterns only bind
>one). Consider the pattern ``C D'', where C and D are constructors.
>This patterns is syntactically ambiguous: is it the application of
>constructor C to constructor D, or two successive parameters,
>parameter C followed by parameter D ? In a function pattern the first
>interpretation is used, in a fun pattern the second one is assumed
>(hence, when you need the first meaning in a fun pattern you must
>bracket the application of constructor C to D, writing (C D)).

I appreciated the reason for the existance of "function", I 
just hadn't realised that or patterns are not considered basic.

>Library considerations:
>-----------------------

( 
  Important comment --- I realise that the implementations I
  gave for the routines below are far from optimal, and just
  provided them as a definition for exactly what I meant the
  routine to do, such as 

>> let list_of_n n x = list_of_vect (make_vect n x);;

  whose operation is more transparent than a more efficient
  version. I understand the dislike of increasing the core
  library...it is mainly the assymetries that I missed...I would
  see that there existed map for lists and map for vects, and assumed
  that the other things would carry over. Similarly for compy_vect
  and copy_string. 
)

The examples you gave of similar functions to mine --- were they
from the caml 3.1 library? Can this library be used with caml-light?

>Packed arrays:
>--------------
>
>>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.
>
>Why do you want them packed ? You can use vectors. I agree that in
>some cases vectors waste memory locations, in particular for caracters
>(but Caml provides strings).
>In some cases, you can consider to use bit_vectors (I can send you such a
>library if you want), otherwise you can use integers and logical
>shift operations as in C, but this is very low-level. The best
>solution is probably to consider these packed arrays as a compiler
>optimisation, but is it worth the work it needs ?

Unfortunately it is worth the work. One of my main applications spends most
of its time testing, compying, manipulating, etc. some arrays of up to
about 30 terms where each element is 1 bit --- perfect for using integers,
especially since some of the most frequent operations naturally become bit
shifts and logical operations. Unfortunately, I now have to change this
to two bits per element, which means they will no longer for into an
integer...and jumping up to 30 element arrays (120 bytes) is a little more 
inefficient than I would like. Especially since I have to store many
of them permanently and memory use (70MB or so) is becoming a problem.

I would appreciate the bit_vector library thanks.

>Unary minus:
------------
> [ there is a really tough syntactical problem ]

I understand this problem. I cannot suggest a good solution. I'm
just commenting that it is an annoyance for me (which will probably
go away with practice).

>Extended pattern matching:
>--------------------------
>
>>        - 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
>>                ;;
>
>You can encode this using a guard (a ``when'' side-condition) in your
>pattern matching clause:
>let compare = function
>  | (x, y) when x = y -> 0
>  | (x, y) -> if x > y then 1 else -1;;
>compare : 'a * 'a -> int = <fun>
>
>>         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.
>
>You're right. It is conceivable to add this kind of ``non-linear''
>patterns to Caml: the compiler just has to generate the right ``when''
>conditions. This may be done some day. This was not done to maintain a
>good property of Caml pattern matching: pattern matching selection
>is fast, and in particular it cannot loop for ever. In the presence of
>cyclic data, the equality test generated by non linear patterns may
>need an unpredictable amount of computation to complete, or may even
>loop for ever.
>
>In fact we prefered to implement guards rather non linear patterns,
>since guards are more general, allowing to test not only variable
>equalities but arbitrary boolean conditions (in particular they allow
>user defined equality rather than the built-in ad hoc equality).

I realise that guards are more general, and I use them extensively.
It is just that testing for equality in a guard is less readable
(in my opinion --- I realise that it forces you to notice the 
duplication) than having it in the pattern. I.e.

>>                        | x x -> 0

is more readable than

>  | (x, y) when x = y -> 0

By the way: I apologise if I seem like I am complaining... I
know that such an implementation takes time and has other tradeoffs, 
I'm just putting in my opinion for what should take precedence
in future work.

>Continue in patterns:
>---------------------

> [ It exists in Caml V3.1 ]

>Generalized orpats:
> -------------------

> [ It exists in Caml V3.1 ]

>Definitions of record values:
>-----------------------------
>
>>        - 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 th
>+ e
>>          appropriate values. Why? So I can write a program that has lots of
>>          things that it will eventually do with slight changes to a structur
>+ e,
>>          and I don't have to go through and change routines that are 
>>          irrelevant to the change.
>
>This a well known problem: allocation of record values is much more
>messy than allocation of sum type values. As you mentioned, this is
>particularly evident when you have to modify a few part of a given
>record.

>However, in Caml you get the capability to treat the fields that have to be
>modified in an imperative way: you just declare those fields ``mutable''
>when defining the record type. This way you share the record and its
>modified version, and just have to change what have to be modified.
>Your example would be something like:
>r -> r.Field3 <- 5; r.Field7 <- 9; r
>
>Unfortunately, when you need a new (fresh) data structure, this
>solution does not work.
>Some partial solutions have been proposed: for instance Caml V3.1 provides a
>short-hand to define the content of a record field: when no expression
>is associated to a field name then a variable expression equal to the
>field name is assumed.
>This way { x; y} is read as {x = x; y = y}. Your example is then a bit
>simplified 
>{ Field1; Field2; Field3; Field4; Field5; Field6; Field7 } ->
>{ Field1; Field2; Field3 = 5 ; Field4; Field5; Field6; Field7 = 9 }
>
>Unfortunately, this does not solve your maintenance problem.
>By contrast, your generalised ellipse is an exiting alternative, since
>it allows an easy modification of allocating routines.

I ended up using a list of sum type values, and had specialised
routines that went through and extracted/modified/whatever the 
particular value. For the specific application I was using, there 
were only 2 or 3 or so terms in it in any specific compilation, so
efficiency was not a big problem here. I considered making everything
mutable and then making a mutable_structure_copy function (perhaps in C), but
that seemed rather ugly.


>Overloading:
>------------
>>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 ...
>
>This is really difficult to provide, and is a long-time research problem.
>However, there exists a restricted form of overloading in Caml V3.1
>that we called ``static overloading''.
>
>We recently made progress on that point and proposed new type systems
>and new compilation schemes to provide a general overloading facility
>(see the article ``Extensional Polymorphism'' in POPL 95).
>This work still has to be fully incorporated into a working Caml system.

Great!

Thanks for your comments,

				Andrew.





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

* Re: Constructive criticism
  1995-08-29 17:55 Constructive criticism Pierre Weis
  1995-08-29 18:08 ` Pierre Weis
@ 1995-08-30 13:34 ` Xavier Leroy
  1 sibling, 0 replies; 4+ messages in thread
From: Xavier Leroy @ 1995-08-30 13:34 UTC (permalink / raw)
  To: Andrew Conway; +Cc: Pierre.Weis, Valerie.Menissier

Thank you for your valuable comments. I don't have much to add to
Pierre Weis's reply:

>      - There seems to be a bug in the string_of_num routine in
>        the contributed libnum package:

Right. Valerie Menissier-Morain and I have just fixed it. The patch is
at the end of this message.

>        Some other routines that I expected that were not present:
>              sprintf ( given so many other printf variants )

printf and eprintf are trivial partial applications of fprintf, but
sprintf needs a totally different implementation, which is why it was
left out originally. The next release of Caml Light will have it.

>              copy_string ( given copy_vect )

The next release of Caml Light will have it, too.

>      - 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'd love to have that, too. Unfortunately, it's slightly harder to
compile than "when" because "fail" can occur arbitrarily deep in the
r.h.s., so in general one has to restore the stack to its original
status before going on with the matching. The current back-end of the
Caml Light compiler cannot handle this.

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

Again, this cannot be supported by the current compiler, because of
the way it accesses pattern variables in the r.h.s. of matchings.

Regards,

- Xavier Leroy

Index: camllight/sources/contrib/libnum/nat.mlp
diff -c camllight/sources/contrib/libnum/nat.mlp:1.2 camllight/sources/contrib/libnum/nat.mlp:1.3
*** camllight/sources/contrib/libnum/nat.mlp:1.2	Wed Jan 04 14:49:27 1995
--- camllight/sources/contrib/libnum/nat.mlp	Wed Aug 30 15:01:41 1995
***************
*** 239,251 ****
  #ifdef SIXTYFOUR
  let max_superscript_10_power_in_int = 18;;
  let max_power_10_power_in_int = nat_of_int 1000000000000000000;;
- let raw_string_of_digit_vect =
-     [| "0000000000000000000"; "00000000000000000000" |];;
  #else
  let max_superscript_10_power_in_int = 9;;
  let max_power_10_power_in_int = nat_of_int 1000000000;;
- let raw_string_of_digit_vect =
-     [| "0000000000" |];;
  #endif
  
  let raw_string_of_digit nat off =
--- 239,247 ----
***************
*** 257,284 ****
         let leading_digits = nth_digit_nat A_2 0
         and s1 = string_of_int (nth_digit_nat A_1 0) in
         let len = string_length s1 in
!        if lt_int leading_digits 10 
!           then begin
!                let result = raw_string_of_digit_vect.(0) in
!                set_nth_char result 0 
!                             (char_of_int (add_int 48 leading_digits));
!                blit_string s1 0 
!                     result (sub_int max_superscript_10_power_in_int len) len;
!                result
!                end 
!        else begin
!             let result = raw_string_of_digit_vect.(1) in
              blit_string (string_of_int leading_digits) 0 result 0 2;
!             blit_string s1 0 result 
!                  (sub_int max_superscript_10_power_in_int len) len;
              result
-            end
         end
  ;;
  
! (* XL: suppression de string_of_digit *)
  
! 
  let sys_string_of_digit nat off =
      let s = raw_string_of_digit nat off in
      let result = create_string (string_length s) in
--- 253,280 ----
         let leading_digits = nth_digit_nat A_2 0
         and s1 = string_of_int (nth_digit_nat A_1 0) in
         let len = string_length s1 in
!        if lt_int leading_digits 10 then begin
!             let result = make_string (max_superscript_10_power_in_int+1) `0` in
!             set_nth_char result 0 
!                          (char_of_int (add_int 48 leading_digits));
!             blit_string s1 0 
!                  result (sub_int (string_length result) len) len;
!             result
!        end else begin
!             let result = make_string (max_superscript_10_power_in_int+2) `0` in
              blit_string (string_of_int leading_digits) 0 result 0 2;
!             blit_string s1 0 
!                  result (sub_int (string_length result) len) len;
              result
         end
+   end
  ;;
  
! (* XL: suppression de string_of_digit et de sys_string_of_digit.
!    La copie est de toute facon faite dans string_of_nat, qui est le
!    seul point d'entree public dans ce code. *)
  
! (******
  let sys_string_of_digit nat off =
      let s = raw_string_of_digit nat off in
      let result = create_string (string_length s) in
***************
*** 286,293 ****
      s
  ;;
  
- (******
- 
  let string_of_digit nat =
      sys_string_of_digit nat 0
  ;;
--- 282,287 ----
***************
*** 440,446 ****
  let unadjusted_string_of_nat nat off len_nat =
    let len = num_digits_nat nat off len_nat in
    if len == 1 then
!        sys_string_of_digit nat off
    else
         let len_copy = ref (succ len) in
         let copy1 = create_nat !len_copy
--- 434,440 ----
  let unadjusted_string_of_nat nat off len_nat =
    let len = num_digits_nat nat off len_nat in
    if len == 1 then
!        raw_string_of_digit nat off
    else
         let len_copy = ref (succ len) in
         let copy1 = create_nat !len_copy




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

end of thread, other threads:[~1995-08-30 17:20 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1995-08-29 17:55 Constructive criticism Pierre Weis
1995-08-29 18:08 ` Pierre Weis
1995-08-30 13:07   ` Andrew Conway
1995-08-30 13:34 ` Xavier Leroy

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).