Version française
Home     About     Download     Resources     Contact us    
Browse thread
Re: [Caml-list] Future of labels
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: Jacques Garrigue <garrigue@k...>
Subject: Re: [Caml-list] Future of labels, and ideas for library labelling
Hi Patrick,

This is only a point by point answer.

On labels vs. extensible records:
> > I'm not really convinced of that. SML for instance has structural
> > records, and uses them in its basis library. You can look at the result
> > for yourself. For me it's only half the way.
[...]
> I think that we're in agreement here.  Structural records like SML is a
> start, but light-weight extensible records would address most of these
> issues.
> 
>   - Labeled arguments are included in a record, and unlabelled arguments
> are outside of the record.  And since they are light-weight, there is no
> need to declare a type definition for the record. 

That's exactly what I was pointing as a weaker form of commutation:
labeled arguments commute between themselves, but they do not commute
with non-labeled arguments.

>   - Labels and currying do give a nicer syntax.  On the other hand, not
> having good support for records is a detriment to the syntax. Most
> programmers coming to Caml will have an expectation that fields can belong
> to more than one record.  Luckily, labelled arguments removes at least one
> reason for light-weight records. 

I know the lack of light-weight records is a pain, but we have already
two record-like structures in OCaml, and tuples. Predefined records
have their advantages, so this would mean adding yet another
structure. This may happen someday, but I'm not all that
enthusiastic.

>   - Optional arguments can be addressed by having a value which
> contains the default arguments which is modified by a record update
> syntax.

This handles only default arguments, optional arguments are more
powerful since their value may be computed at call time.


On proper labellings:
> > I have also eta-expanded more than necessary, to make the code more
> > readable.
> > We can write something shorter if we use labels as they were in ocaml
> > 2.99, before their trimming:
> >    List.fold_left lists ~acc:IntSet.empty
> >      ~f:(List.fold_left ~f:(fun ~acc item -> IntSet.add acc ~item))
> > Now, which is the more readable program, this one or yours.
> 
> Hmm... hard to say. Using this API, I would wonder why isn't there a label
> for the list? It would be much simpler if every argument to a function had
> to have a label.  I know this presents its own problems, but it adds to
> the things one must remember for coding.

I think this is explained in the tutorial: you should not label the
object of the operation. Normally one learns that in elementary
school, but forgets it soon after, so it can be a bit difficult.
Requires some practice before it comes out naturally.

> Regarding Haskell, what you say is surprising since I would classify
> a common use of monadic binding as a folding function. For the operator
> (>>=) which has type
> 
>        (>>=) :: m a -> (a -> m b) -> m b
> 
> if a and b are the same type than it is a folding over computation state.
> This is certainly a common use in real programs.

I was only talking of list folding functions.
Labels are not the only way to improve readability. Infix operators
can also help.


On type errors in label mode:
> Forgetting to use the label in commuting mode can lead to incredible
> cryptic error messages.

The situation has improved a bit with 3.01.
Give it a try to see the difference. This is not perfect yet, but if
you see something clearly wrong you can send a bug report.

> As discussed above, I like to use a variant of
> list folding that gets the arugments in the "right" order and is
> tail-recursive. I tried adding labels to the arguments to see what would
> happen when they were omitted.  The result was pretty surprising: 
> 
> val listFold : f:('a -> 'b -> 'b) -> l:'a list -> acc:'b -> 'b
> 
> let cons x l = x :: l
> 
> listFold cons (listFold cons [5;4;3] []) [];; 
> 
> While this is a contrived example to reverse a list twice, not including
> the labels gave this impressive type back from the compiler:
[monstruous type]

This problem is specific to functions returning a polymorphic type:
if your arguments match none of the labels in the function type, they
will be seen as arguments to the result of the function, producing a
huge type by unification.

If you had tried on an instanciated typed, you would have got a more
reasonable answer.

# let rec listFold ~f ~l ~(acc : int) =
    match l with [] -> acc
    | x :: l -> listFold ~f ~l ~acc:(f x acc);;
val listFold : f:('a -> int -> int) -> l:'a list -> acc:int -> int = <fun>
# let cons x l = x :: l;;
val cons : 'a -> 'a list -> 'a list = <fun>
# listFold cons (listFold cons [5;4;3] []) [];; 
Expecting function has type
  f:('a -> int -> int) -> l:'a list -> acc:int -> int
This argument cannot be applied without label

When there is enough information, one can produce accurate error
messages.

> I think this is more than enough to frighten me from using commuting label
> mode.  The classic mode seems to give more sensible error messages.

In practice, I do not bump into this kind of errors very often.
In real programs, functions returning a polymorphic variable as result
are not so frequent.

> Another language that I'm very familiar with that has labelled arguments
> (in some sense) is Verilog.  Instantiation by named connection is
> really crucial to using the language safely. Some observations though:
> 
>   1) There are no structures in the language, so some need of labelling is
> needed.

Indeed, you will fell more directly need for labels in dynamically
typed languages.
But, while this may be true that labels are less needed from the
point-of-view of type safety, for documentation the need is identical.
Particularly in ML you don't write type annotations, and it is often
hard to follow the role of a variable in a program. Ocamlbrowser can
give you this information, but this does not replace information about
the role of an argument, which appears to be most needed when reading
a program.

>   2) There is no partial application which makes it easier to give
> intelligent error messages.

But partial application makes commutation more interesting :-)

Thanks for all these good points.

       Jacques
-------------------
To unsubscribe, mail caml-list-request@inria.fr.  Archives: http://caml.inria.fr