Browse thread
Labels and polymorphism
[
Home
]
[ Index:
by date
|
by threads
]
[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: | 2007-03-08 (23:42) |
From: | Nathaniel Gray <n8gray@g...> |
Subject: | Re: [Caml-list] Labels and polymorphism |
On 3/8/07, Roland Zumkeller <roland.zumkeller@gmail.com> wrote: > On 08/03/07, Nathaniel Gray <n8gray@gmail.com> wrote: > > # let f ~x = x;; > > val f : x:'a -> 'a = <fun> > > # f ~x:1;; > > - : int = 1 > > # f 1;; > > - : x:(int -> 'a) -> 'a = <fun> > > The "1" is assumed to be an argument to "f ~x:a" (where "a" is yet to > be given). Therefore "f ~x:a" must be of type "int -> ...". Now "f > ~x:a" is of the same type as (and here actually reduces to) "a". > Hence this type for the x-labeled argument. > > Perhaps looking at this might help, too: > # f 1 1 1;; > - : x:(int -> int -> int -> 'a) -> 'a = <fun> Ok, I think maybe I've got it. The problem is the equivalence between: let f ~x ~y = ... and let f ~x = (fun ~y -> ... ) Or in other words, you have to understand that all functions in ocaml have just one parameter (at least as far as the type system is concerned), so "total application" is tricky to figure out. The more enlightening example, IMHO, is this one: # let f ~x = x;; val f : x:'a -> 'a = <fun> # f 10 ~x:(fun x -> x+1);; - : int = 11 In a multi-argument-function world the second line makes no sense. Labeled arguments should allow you to rearrange the (multiple) arguments of the current application, but not interleave them with arguments from upcoming applications! Enlightenment blossoms when you realize that that's actually the thing that labeled arguments *do* allow you to do. Another helpful example: # let f ~x = x;; val f : x:'a -> 'a = <fun> # let g ~y = f;; val g : y:'a -> x:'b -> 'b = <fun> # g ~x:3 ~y:5;; - : int = 3 > Now you ask, why are things as they are? Why can't OCaml guess that > the "1" was meant for the label "x"? > > Probably it could, but with such a typing rule we would have to write > "(fun ~x:a -> f ~x:a 1)" for what is currently "f 1" (partial > application would be essentially lost here). In contrast, becoming > able to write "f x" instead of "f ~x:1" seems not enough of a gain to > compensate this. You could do it by using the rule that applying an unlabeled argument in a labeled context always binds to that label, but applying a labeled argument in an unlabeled context (or one where the labels don't match) defers the application until the label is found. (Maybe this is what you're hinting at?) So if you define f like this: let f a b ~c x ~y ~z = z Then you could apply it in one of these ways: f 1 2 3 4 5 6 f 1 2 3 4 ~z:6 ~y:5 f ~c:3 ~z:6 1 2 4 5 But not this way: f 1 2 4 ~c:3 5 6 (* Too late -- c is already bound to 4 *) f 1 2 ~y:5 4 ~c:3 6 (* Ditto *) As a practical matter you would probably want to label a suffix of your arguments for maximum flexibility. You would lose the ability to do *some* (dare I say unimportant?) partial applications, but this approach seems much more intuitive to me. Mainly it has the advantage that adding labels to a function would never break existing calls to that function. This property seems highly desirable to me -- so desirable that I'm downright astonished it isn't already true. Thanks for helping, -n8 -- >>>-- Nathaniel Gray -- Caltech Computer Science ------> >>>-- Mojave Project -- http://mojave.cs.caltech.edu -->