From mboxrd@z Thu Jan 1 00:00:00 1970 Received: (from weis@localhost) by pauillac.inria.fr (8.7.6/8.7.3) id JAA12955 for caml-redistribution; Thu, 7 Oct 1999 09:56:29 +0200 (MET DST) 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 UAA26503 for ; Wed, 6 Oct 1999 20:45:31 +0200 (MET DST) Received: from isil.maya.com (isil.maya.com [192.70.254.5]) by nez-perce.inria.fr (8.8.7/8.8.7) with ESMTP id UAA16478 for ; Wed, 6 Oct 1999 20:45:28 +0200 (MET DST) Received: (from prevost@localhost) by isil.maya.com (8.9.3/8.9.3) id OAA01833; Wed, 6 Oct 1999 14:50:46 -0400 Sender: weis To: Ohad Rodeh Cc: caml-list@inria.fr Subject: Re: Stdlib regularity References: From: John Prevost Date: 06 Oct 1999 14:50:46 -0400 In-Reply-To: Ohad Rodeh's message of "Wed, 6 Oct 1999 09:25:53 -0400 (EDT)" Message-ID: User-Agent: Gnus/5.070096 (Pterodactyl Gnus v0.96) Emacs/20.4 MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Ohad Rodeh writes: > I have used OCaml extensively in the past few years, and I've had > some misgivings about the CAML standard library argument ordering. It > is a little bit confusing and not standard. For example: > > val Queue.add: 'a -> 'a t -> unit > val Hashtbl.add: ('a,'b) t -> 'a -> 'b -> unit > > My general suggestion is to always make the first argument the <'a t> > type and the second the <'a> type. The only exception to this rule > should be functionals, for example, in Queue: > > val iter: ('a -> unit) -> 'a t -> unit I have a slightly different proposal, but one which is along the same lines: Standard ordering is: val ho_func : ('a -> unit) -> 'a t -> unit val ho_func : ('a -> 'b) -> 'a t -> 'b t val imp_func : 'a t -> 'a -> unit val func : 'a -> 'a t -> 'a t Rationale: The basic rationale is that the most often-repeated item should be at the front to make it easier to curry. Along with this, there's the desire to have a consistent style for ordering arguments. The basic style I propose is that for functions acting on some sort of agregate data type the "importance" of the arguments is as follows: Any higher-order function gets its function arguments first. (Idea: the function argument determines the meaning of the function. Hence it should be closer to the function than the other arguments. Corollary: non-function arguments that determine the meaning of a function should also bind closely.) In an imperative case, the agregate argument should come next, after any behavior-determining arguments, but before any single values. (Idea: in an imperative case, the value "acted upon" is more important than the value used in the action--sort of like direct object vs. indirect object.) i.e. give john pizza ==> john is the "aggregate", pizza is the value used in the action. In the non-imperative case, the "value" place should come before the aggregate case--this is because we're no longer "acting on" something. Now that we're not, the value determines the meaning of the function which is applied to the aggregate, returning a new aggregate. In essence, the function should be thought of in this case as taking an argument and returning a new function, like map does, rather than acting on something after receiving multiple arguments. So, the basic ordering: val func : determiners -> arguments -> result val Queue.add : 'a t -> 'a -> unit + val Hashtbl.add : ('a,'b) t -> 'a -> 'b -> unit + val Queue.iter : ('a -> unit) -> 'a t -> unit val Stream.npeek : int -> 'a t -> 'a list * val S.add : key -> 'a -> 'a t -> 'a t * val S.find : 'a t -> key -> 'a * val S.remove : key -> 'a t -> 'a t * val S.mem : key -> 'a t -> bool * ... The * is where I disagree with Ohad's strategy. The + is where I disagree with O'Caml's. As a note, O'Caml's strategy makes imperative functions order arguments more like pure functions. This may make the default currying order less useful, but is probably better than my strategy. Hence, O'Caml's order is pretty good. :) John.