From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: weis Received: (from weis@localhost) by pauillac.inria.fr (8.7.6/8.7.3) id PAA08394 for caml-redistribution@pauillac.inria.fr; Tue, 21 Mar 2000 15:07:59 +0100 (MET) Resent-Message-Id: <200003211407.PAA08394@pauillac.inria.fr> Received: from nez-perce.inria.fr (nez-perce.inria.fr [192.93.2.78]) by pauillac.inria.fr (8.7.6/8.7.3) with ESMTP id DAA12856 for ; Thu, 16 Mar 2000 03:53:52 +0100 (MET) Received: from kurims.kurims.kyoto-u.ac.jp (kurims.kurims.kyoto-u.ac.jp [130.54.16.1]) by nez-perce.inria.fr (8.8.7/8.8.7) with ESMTP id DAA06234; Thu, 16 Mar 2000 03:53:49 +0100 (MET) Received: from localhost (sansho.kurims.kyoto-u.ac.jp [130.54.16.90]) by kurims.kurims.kyoto-u.ac.jp (8.9.3/3.7W) with ESMTP id LAA10910; Thu, 16 Mar 2000 11:53:47 +0900 (JST) To: Pierre.Weis@inria.fr Cc: caml-list@inria.fr Subject: Re: Syntax for label, NEW PROPOSAL In-Reply-To: Your message of "Wed, 15 Mar 2000 14:58:30 +0100" <20000315145830.22463@pauillac.inria.fr> References: <20000315145830.22463@pauillac.inria.fr> X-Mailer: Mew version 1.93 on Emacs 20.5 / Mule 4.0 (HANANOEN) Mime-Version: 1.0 Content-Type: Text/Plain; charset=us-ascii Content-Transfer-Encoding: 7bit Message-Id: <20000316115540L.garrigue@kurims.kyoto-u.ac.jp> Date: Thu, 16 Mar 2000 11:55:40 +0900 From: Jacques Garrigue X-Dispatcher: imput version 980905(IM100) Resent-From: weis@pauillac.inria.fr Resent-Date: Tue, 21 Mar 2000 15:07:59 +0100 Resent-To: caml-redistribution@pauillac.inria.fr From: Pierre Weis > > *** Proposal > > > > Objective Caml 3.00 is not yet released, and I believe we can still > > have modifications on this point. > > Yes, you're perfectly right, we can still modify several points. > However, I think there are many other points that are more important > than the choice of ``%'' instead of ``:'', which is only cosmetic > after all. Well, I think I've got enough reactions to rule out %. These are of the small details of syntax you want to check for sure. And that are very hard to change afterwards. > Thus, I would prefer to discuss deeper and more semantic problems: > > -- Problem1: labels can be reserved keywords. This is questionable > and it has been strongly criticised by some Caml users, especially when > reading in the code the awful sequence fun:begin fun ... Well, maybe just because I've grown used to it, I do not find it awful at all. The rationale behind allowing the use of keywords as labels is that there are lots of keywords in Caml, and many of them are good candidates for labels. Not allowing them makes often choice more difficult, or forces to use longer names. On the other hand, their particular use in the standard library may be another subject of discussion. If I remember correctly, there are only 2 keywords used as label in the standard library: `fun' (in functionals) and `to' (in output functions). If we want to remove them, I think a good policy would be to change the "default" length of labels from 3 to 4. Since many Caml keywords are of length 3, we avoid lots of conflicts! This would mean: fun -> func to -> chan or dest acc -> accu :-) src -> orig (src meant a lot to a now disappeared company) dst -> dest (maybe because I'm French, dst reminds me of something) buf -> buff ??? ... Still it seems reasonable to keep pos: and len:. Beware however that label changes are inherently dangerous: you often realize afterwards that a choice was not so good, and I really hoped that we could definitively fix the standard library labels in 3.00. > -- Problem2: labels that spread all over the standard libraries, even > when they do not add any good. Well, the current policy (as defined in the manual) is to put labels on at least all arguments but one (with some very special exceptions like printf). This is necessary to allow commuting between arguments, which is also an important theme of labels. As such I would not say that they do not do any good. > I would cite: > > * the labels completely redundant with the types > (E.g. char:char in the type of String.contains or String.index) Following the above policy, I would say that these are not ideal choices, but then what other possibility is there? Moreover, even if this label is redundant in types, it is not necessarilly so in code. > * undesired labels: in many cases I don't want to have labels just > because I don't want to remember their names. (E.g., I very often > mispell the label acc since I've always used accu to name an > accumulator; furthermore, when I do not mispell this label, I feel > acc:accu extremely verbose). Also because labels are verbose at > application. Isn't there a classic mode for that? If you think that labels are verbose, you can use it, and it even provides some partial support for label checking when you want it. I suppose we should have a precise idea of what labels are there for. For me they are a systematic mechanism, and the fact we allow to have no label on one argument in function types is just a little comfort, particularly useful when working with functionals. > * labels that prevent you to use comfortably your traditional functions. > This is particularly evident for the List.map or List.fold_right > higher-order functionals. > > This last point is a real problem. Compare the usual way of using > functionals to define the sum of the elements of a list: > > # let sum l = List.fold_right ( + ) l 0;; > val sum : int list -> int = Whether you consider this readable or not is a question of taste. I personally believe that you need quite a background in HO formalisms to understand the above. But of course most current Caml users have this background. > # let sum l = List.fold_right ( + ) l 0;; > ^^^^^ > This expression has type int -> int -> int but is here used with type 'a list Aargh, that's right, error messages are a pain. I believe I worked a lot making them informative, but there are still difficult situations. I'll try to improve this. Remark however that, in modern mode, it is already strange to have an application with no labels at all... > The real problem is that fixing the code makes no good at all to its > readability (at least that's what I would say): > > # let sum = List.fold_right fun:begin fun x acc:y -> x + y end acc:0;; > val sum : 'a -> int list -> int = You do not have to use begin .. end everywhere. I do personally write: # let sum = List.fold_right acc:0 fun:(fun x :acc -> x + acc);; Remark that here you didn't care about whether acc is the first or second argument of the passed function, just because (+) is commutative. However, in general functions are not commutative, and I always have to think a lot when using List.fold_left or List.fold_right without labels, just because I may write wrong code without the type checker telling me anything. > For all these reasons, I would suggest to carefully use labels into > the standard libraries: > > -- remove labels from higher-order functional > -- remove redundant labels: when no ambiguity can occur you need not > to add a label. > -- use labels when typechecking ambiguity is evident (for instance > when there are two or more parameters with the same type). > > Labels must enforce readability of code or help documenting the > libraries, it should not be an extra burden to the programmer and a > way of offuscating code. This seems to boil down to using labels for documentation purposes only. If you reduce them to such an extent, I'm afraid they will not do very much for code readability anymore. And I stated above, you get typechecking holes in functionals. By the way, I do not see how labels can help obfuscating code. What you are probably intending to say is that they make more difficult to write some combinator-based HO-style code. Does it mean we should have a version of the List module without labels for such uses? > Evidently, as any other extension, labels must not offuscate the > overall picture, that is they must not clobber the semantics, nor add > extra exceptional cases to the few general rules we have for the > syntax and semantics of Caml. > > In this respect, optional labelled arguments might also be discussed, > particularly for the following facts: > > -- syntactically identical patterns and expressions now may have > incompatible types: > # let f ?style:x _ = x;; > val f : ?style:'a -> 'b -> 'a option = > > As a pattern on the left-hand side x has type 'a, while as an > expression on the right hand side it has type 'a option Well, internally the left-hand side is also 'a option, but option is abbreviated because it is redundant. I do not think people want to see the left-hand side option, but maybe this technical part should be made more explicit in the manual. Conversion from 'a to 'a option is done at application. I do not think there is any semantical problem here. > -- some expressions can be only written as arguments in an application > context: > # let f ?style:x g = ?style:x;; ?style:x is not an expression: labels are part of the application node, not of the arguments. > -- the simple addition of a default value to an optional argument may > trigger a typechecking error: > > # let f ?(style:x) g = g ?style:x;; > val f : ?style:'a -> (?style:'a -> 'b) -> 'b = > > # let f ?(style:x = 1) g = g ?style:x;; > This expression has type int but is here used with type 'a option That one is more serious. This is not a "simple addition". Default values unroll some syntactic sugar, changing the type of the argument. Whether this is a good idea to have such syntactic sugar in the language is an interesting question. However I believe it provides some real comfort. > Do not forget the design decision that has always been used before in > the development of Caml: interesting but not universal extensions to > the language must carefully be kept orthogonal to the core language > and its libraries. This has been successfully achieved for the > important addition of modules (that do not prevent the users from > using the old interface-implementation view of modules) as well as for > the objects system addition that has been also maintained orthogonal > to the rest of the language (in particular the standard library has > never been ``objectified''). I don't know of any reason why labels > cannot follow the same safe guidelines. I just believed that it was agreed that labelizing the standard library was a progress. Of course this also means that you do not stay 100% compatible in modern mode. Still, there are no optional arguments in the standard library, meaning that you stay 100% compatible in classic mode. > There are also people around that would like to keep Caml a true > functional language, where usage of higer order functions is easy and > natural. We have to be careful not to lose what is the actual > strength of the language. Of course, I agree with that. A first approach would be to say that one can always use classic mode. Modern is not pedantic, it is just another typing discipline. But this would endanger the unicity of the language, so this cannot be an universal answer. Now, the problem we are talking about seems to boil down to higher order functions in modern mode. And more particularly List.fold_left and List.fold_right, since these are about the only two functions where the argument itself has labels. It would cost nothing to add 4 more unlabelled functions to the List module. val foldl : fun:('a -> 'b -> 'a) -> 'a -> 'b list -> 'a val foldr : fun:('a -> 'b -> 'b) -> 'a list -> 'b -> 'b val foldl2 : fun:('a -> 'b -> 'c -> 'a) -> 'a -> 'b list -> 'c list -> 'a val foldr2 : fun:('a -> 'b -> 'c -> 'c) -> 'a list -> 'b list -> 'c -> 'c This way you can write # let sum l = List.foldr fun:(+) l 0 The same additions would also apply to the Array module. There is also the problem of iteri and mapi, where i: may be not that important in practice (even when working on an array of integers, I wouldn't expect anybody to make such a mistake). val iteri : fun:(i:int -> 'a -> unit) -> 'a array -> unit val mapi : fun:(i:int -> 'a -> 'b) -> 'a array -> 'b array One may even insist that fun: is superfluous. Then it would probably be better to have another List module without labels at all. Again, this is pretty easy to do, and does not incur any code blow in general. Or do you think that the problem is deeper, and that labels are breaking the foundations of the language ? Amicalement, Jacques --------------------------------------------------------------------------- Jacques Garrigue Kyoto University garrigue at kurims.kyoto-u.ac.jp JG