caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* What will the new syntax be like? (O'Caml + O'Labl)
@ 1999-12-06  3:05 John Prevost
  1999-12-06 11:05 ` Jacques Garrigue
  0 siblings, 1 reply; 6+ messages in thread
From: John Prevost @ 1999-12-06  3:05 UTC (permalink / raw)
  To: caml-list

Can we get any hints on what the syntax of the O'Labl features in the
new O'Caml will be like?  I do like the polymorphic variants and
tagged/optional argument features of O'Labl, but I'm not too keen on
their syntax:

let foo bar:a zub:b ?qux:c [< 10 >] ?woz:d =
  match d with
    | None -> a + b + c
    | Some x -> a + b + c + d

Things which freak me out:

  a) the ident1:ident2 syntax for labels is maybe convenient, but the
     fact that : is already used for types and that this requires : to not
     have whitespace around it is pretty nasty.

  b) the ?... syntax for optional stuff is pretty abominable.
     Combined with the : syntax, the definition of a function starts
     to look like gibberish.

  c) the ?... [< ... >] syntax for providing a default value for an
     optional argument adds to the pain, since [< ... >] is already
     used by parsers, and its heaviness combined with the ?s lightness
     makes it really obscure what a line like the above means.

  d) not illustrated above, the use of ` for polymorphic variants is
     also pretty ferociously confusing--mainly because ` and ' are
     sometimes difficult to tell apart, and because I could now say
     something like:

     let foo = parser [< '`foo 'a' >] -> ...

     which is parsable, but nasty.

  e) The type expressions that come out are sometimes nasty looking as
     well:

     'a[> 'int int | 'float float]

     which is actually not that bad, except for the 'a part which is
     quite unlike other self-referential types in O'Caml.  (Why not
     something like objects: [> 'int int | 'float float ] as 'a?)

I just sucked down the O'Caml CVS version and have played with it a
bit trying to figure out what syntax is in the works.  As far as I can
tell, the : is still being overloaded as above, and ? is being used
too, but [< ... >] has been changed (to something like {= ...} ?  I
can't entirely tell, because if I try to use it I always get a "This
optional argument cannot be erased" warning.

Anyway, what's in store for us in the next version of O'Caml?  I've
thought Caml's syntax the cleanest of the ML family for some time, but
warts like the above could make me change my mind.

John




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

* Re: What will the new syntax be like? (O'Caml + O'Labl)
  1999-12-06  3:05 What will the new syntax be like? (O'Caml + O'Labl) John Prevost
@ 1999-12-06 11:05 ` Jacques Garrigue
  1999-12-07  7:35   ` John Prevost
  0 siblings, 1 reply; 6+ messages in thread
From: Jacques Garrigue @ 1999-12-06 11:05 UTC (permalink / raw)
  To: prevost; +Cc: caml-list

From: John Prevost <prevost@maya.com>

> Can we get any hints on what the syntax of the O'Labl features in the
> new O'Caml will be like?  I do like the polymorphic variants and
> tagged/optional argument features of O'Labl, but I'm not too keen on
> their syntax:
> 
> let foo bar:a zub:b ?qux:c [< 10 >] ?woz:d =
>   match d with
>     | None -> a + b + c
>     | Some x -> a + b + c + d

Changes are rather small:

let foo bar:a zub:b ?qux:c{=10} ?woz:d () =
  match d with
  | None -> a + b + c
  | Some x -> a + b + c + d

Notice that you need a non-labeled argument after optional ones, due
to a change in semantics. Optional arguments are now only discarded if
the function is applied to a non-labeled argument appearing after them
the function type.
This change was necessary to resolve some ambiguities, and provide an
untyped semantics for the language.

> Things which freak me out:
> [...]

You may like or not the above notation for labels. We had discussions
here, and the conclusion was that putting spaces around type
annotations was a good thing anyway...

I will not answer in detail your other comments, but yes, the change
in notation for default arguments is to avoid the similarity with
stream parsers.

Variant types have also a cleaned-up syntax, where recursion works
like with objects.

> Anyway, what's in store for us in the next version of O'Caml?  I've
> thought Caml's syntax the cleanest of the ML family for some time, but
> warts like the above could make me change my mind.

It's hard to put that many new features in the language, keeping the
compatibility with all, and obtain a clean syntax. I must admit.
However I think that ocaml3 syntax is reasonable enough, at least
better than olabl's. A second attempt has its advantages.

By the way, the new version is not yet released, so if you have a
coherent syntax to propose for the new features, you can propose.

        Jacques
------------------------------------------------------
Jacques Garrigue, visiting INRIA from Kyoto University
		          Jacques.Garrigue at inria.fr




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

* Re: What will the new syntax be like? (O'Caml + O'Labl)
  1999-12-06 11:05 ` Jacques Garrigue
@ 1999-12-07  7:35   ` John Prevost
  0 siblings, 0 replies; 6+ messages in thread
From: John Prevost @ 1999-12-07  7:35 UTC (permalink / raw)
  To: Jacques.Garrigue; +Cc: caml-list

Jacques Garrigue <Jacques.Garrigue@inria.fr> writes:

> Changes are rather small:
> 
> let foo bar:a zub:b ?qux:c{=10} ?woz:d () =
>   match d with
>   | None -> a + b + c
>   | Some x -> a + b + c + d
> 
> Notice that you need a non-labeled argument after optional ones, due
> to a change in semantics. Optional arguments are now only discarded if
> the function is applied to a non-labeled argument appearing after them
> the function type.
> This change was necessary to resolve some ambiguities, and provide an
> untyped semantics for the language.

Hmm.  This seems like a pain, but I guess I can see the need.  I
always was a little leery of the optional arguments' semantics.

Another thing I've noticed is that non-optional labeled arguments may
have their labels left off.  I wholeheartedly approve of this, since
this was one of my gripes with O'Labl.  (Why should I need to say:
"List.map fun:f l" instead of "List.map f l"?  In many cases, the
label just gets in the way, though it is of help if you're really
going for clarity or you don't know the "standard" order for things
like map.)

The final thing I've noticed in the development version is that I'm
not able to apply labeled arguments out of order.  Is this
intentional, or a side-effect of ongoing work to unify O'Labl and
O'Caml?:

let add :a :b = a + b

# let add :a :b = a + b;;
val add : a:int -> b:int -> int = <fun>
# add b:5 a:3;;
Expecting function has type a:int -> b:int -> int
This argument cannot be applied with label b:

Labels are probably still useful without the potential for
re-ordering, but it does cut down on the utility.  One of the uses I
have for labels is when I have two arguments to a function (say,
List.map), and I want to re-order to make the larger one second.  That
is, it's generally useful for map's first argument to be the function,
but sometimes I want to be able to say:

List.map (short expr of list)
  fun: (long expr
        for the function
        which keeps going)

This follows the natural language model that large complex phrases are
generally not put between a short phrase and the binding phrase--they
reposition to be out of the way.  Having the power to add a short
modifier (fun:) and reorder the expression is a great boon.

> You may like or not the above notation for labels. We had discussions
> here, and the conclusion was that putting spaces around type
> annotations was a good thing anyway...

> It's hard to put that many new features in the language, keeping the
> compatibility with all, and obtain a clean syntax. I must admit.
> However I think that ocaml3 syntax is reasonable enough, at least
> better than olabl's. A second attempt has its advantages.
> 
> By the way, the new version is not yet released, so if you have a
> coherent syntax to propose for the new features, you can propose.

Well, I did some thinking this evening, and here's a summary of where
I went with it.  (I've got what I think is a reasonable and slightly
cleaner proposal near the end, along with a "to my eyes" greatly more
pleasing proposal which would require more parser and lexer changes
(though nothing incompatible).)


The first thought I had was "these optional argument things would be
nicer to read if you could use a keyword to express the optionalness,
rather than a single symbol, and it would also be nice if the equals
sign were more visually bound with the argument".  This led to a
syntax that I feel is too heavy--but I'll show it anyway.  My examples
are based on the following very simple set of functions (in the
current proposed O'Caml 3 syntax):

let div1 num:x den:y = x / y
let div2 :num :den = num / den
let div3 :num ?:den () =
   let v = match den with Some y -> y | None -> 2 in num / y
let div4 num:x ?den:y {= 2} () = x / y

Here's the heavy syntax:

let div1 {| num = x |} {| den = y |} = x / y
let div2 {| num |} {| den |} = num / den
let div3 {| num |} {| optional den |} () = ...
let div4 {| num = x |} {| optional den = y = 2 |} () = x / y

The first problem is seen in div4, where we see that there's a problem
if we wanted to not include the explicit variable binding--I see no
clean way to solve this without an extra special character, which I
was trying to avoid.

The second problem is the weight of {| ... |}, which I thought might
be resolved with:

let div1 {| num = x; den = y |} = ...

and so on.  And a similar syntax for calling.  But this is alien from
the point of view of function application.  So, I dumped this.


The second thing I looked at was the set of "special characters" used
and not used by O'Caml:

Special characters (non-grouping): ~ ` ! @ # $ % ^ & * ' " , . / ? = + \ | - _
Used by O'Caml (library or special): ! @ # $ % ^ & * ' " , . / = + | - _

O'Caml does use ??, but in a very specific circumstance.  I include $
in the specials list because it's used by camlp4.

This leaves us with: ~ ` ? \

Of these, only ~ is allowed as part of a symbolic ident already.

Which leaves: ` ? \

My proposal is that we should avoid further obfuscating the use of
":".  (Not only is it the type operator, but "::" is cons.  And
there's already confusion between the Haskell and ML families in that
the Haskell family does the exact opposite.  No need to add to the
trouble.)

In order to do that, I first picked "\" as the character of
choice--for two reasons:  First, it's a reasonable "separator"
character, like ":" is.  Second, it's used for absolutely nothing at
the moment.  This leads to the following syntax (keeping default
values the same, and changing only the character used.)

let div1 num\x den\y = x / y
let div2 \num \den = num / den
let div3 \num ?\den () = ...
let div4 num\x ?den\y {= 2} () = x / y

as a further refinement, we can unify the use of \ and ? in the
following way:

let div1 num\x den\y = x / y
let div2 \num \den = num / den
let div3 \num ?den = ...
let div4 num\x den?y {= 2} () = x / y
or
let div4 num\x ?den\y {= 2} () = x / y

this last bit is possible since the O'Caml 3 syntax will not allow
unlabeled optional arguments because of the extra unlabelled argument
constraint you mentioned above.

A final possibility, which I think has great merit but may be hard to
parse, is:

let div1 (\num x) (\den y) = x / y
let div2 \num \den = num / den
let div3 \num ?den () = ...
let div4 (\num x) (?den y = 2) () = x / y

I like this last one, since it allows whitespace between the label and
the expression carrying the value, and allows the = to be used in a
more natural way with the label.  Use follows the same pattern:

div4 (\num 5) (\den 5) ()
div2 (\num 5) (\den 2)
div1 (\den 2) (\num 5)

But the parsing, as I said, could be a pain.


Finally, there's the question of type syntaxes for these.  I propose:

val div1 : num\int -> den\int -> int
val div3 : num\int -> den?int -> unit -> int

or

val div1 : num / int -> den / int -> int
...

(Since / doesn't have to bind the same in types, and "int list" looks
bad as "foo:int list" or "foo\int list", but okay as "foo \ int list")

or

val div1 : \num int -> \den int -> int
val div3 : \num int -> ?den int -> unit -> int

(For the (\label expr), (\label pattern) style.)


Finally, if "\" is rejected for labels, I suggest it be used in place
of "`" on variants, since it's much more distinctive than "`" is:

let (+) x y = match (x,y) with
  | `int x, `int y -> `int (x + y)
  | `int x, `float y -> `float (float x +. y)
  | `float x, `int y -> `float (x +. float y)
  | `float x, `float y -> `float (x +. y)

vs

let (+) x y = match (x,y) with
  | \int x, \int y -> \int (x + y)
  | \int x, \float y -> \float (float x +. y)
  | \float x, \int y -> \float (x +. float y)
  | \float x, \float y -> \float (x +. y)

This is of course incompatible with using \ as the label character.


In summary, I think the style which is most aesthetic is that with
(\label expr), (\label pattern), "\label type" where "\" alternates
with "?" rather than adding to it.

I'm perfectly willing to rework the parser and lexer to use this
style.  I can also work my way through the camltk source, but that
will take longer.


John.




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

* Re: What will the new syntax be like? (O'Caml + O'Labl)
  1999-12-07 15:36 Don Syme
  1999-12-07 18:21 ` Markus Mottl
@ 1999-12-07 18:32 ` skaller
  1 sibling, 0 replies; 6+ messages in thread
From: skaller @ 1999-12-07 18:32 UTC (permalink / raw)
  Cc: caml-list

let foo bar:a ?qux:c{=10} : unit = ...

	How do I curry a function with a default argument?
Does

	foo aa

mean

	foo aa 10 (* type unit *)

or is it a function with type int -> unit?

-- 
John Skaller, mailto:skaller@maxtal.com.au
10/1 Toxteth Rd Glebe NSW 2037 Australia
homepage: http://www.maxtal.com.au/~skaller
voice: 61-2-9660-0850




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

* Re: What will the new syntax be like? (O'Caml + O'Labl)
  1999-12-07 15:36 Don Syme
@ 1999-12-07 18:21 ` Markus Mottl
  1999-12-07 18:32 ` skaller
  1 sibling, 0 replies; 6+ messages in thread
From: Markus Mottl @ 1999-12-07 18:21 UTC (permalink / raw)
  To: Don Syme; +Cc: OCAML

> The brackets may not be needed, though I'm not sure...

As a general comment on this thread, I'd like to add that questions of
syntax should take into account the advanced features of modern editors.
It is probably not necessary to force a syntax which explicitely groups
expressions belonging together as long as the parser can group them
without: colorizing and/or font changes done by the editors make things
even more readable.

Regards,
Markus Mottl

-- 
Markus Mottl, mottl@miss.wu-wien.ac.at, http://miss.wu-wien.ac.at/~mottl




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

* RE: What will the new syntax be like? (O'Caml + O'Labl)
@ 1999-12-07 15:36 Don Syme
  1999-12-07 18:21 ` Markus Mottl
  1999-12-07 18:32 ` skaller
  0 siblings, 2 replies; 6+ messages in thread
From: Don Syme @ 1999-12-07 15:36 UTC (permalink / raw)
  To: 'John Prevost', Jacques.Garrigue; +Cc: caml-list


Ignoring the label question, allowing or requiring an explicit keyword for
"optional" and "default" would seem appropriate.  This fits with "mutable" -
we don't have a wierd obscure syntax for that, after all, and that feature
is probably used about as often as these will be.

let foo bar:a zub:b (optional qux:c default 10) woz:d  () =
  match d with
  | None -> a + b + c
  | Some x -> a + b + c + d

One answer to the label question might be to reuse "as".  This is
particularly plausible because labelled parameters now do not have to be
assigned labels at the callsite, so this would not break existing uses of
"as".   Another nice thing may be that the label comes second:  OCaml seems
to have made the "right" choice by putting the name after the "as", rather
than before like SML.  I can't quite express _why_ this is the right choice,
but again and again it feels right to me when I use it in practice.  The
same may turn out to be true for labelled arguments.  

let foo ((e,f) as bar) (b as zub) (optional c as qux default 10) (d as woz)
() =
  match d with
  | None -> a + b + c
  | Some x -> a + b + c + d

The brackets may not be needed, though I'm not sure...
let foo (e,f) as bar   (* comment *) 
        b as zub   (* comment *) 
        optional c as qux default 10 (* comment *) 
        d as woz   (* comment *) 
        () =
  match d with
  | None -> a + b + c
  | Some x -> a + b + c + d

I guess the interpretation of 
let f = function 
  | None as foo -> 0
  | Some x as foo -> x

would also be a labelled function, though one might require the "as" name to
be the same on each branch of the match in order for it to be considered
labelled.

Don

-----Original Message-----
From: John Prevost [mailto:prevost@maya.com]
Sent: 07 December 1999 07:36
To: Jacques.Garrigue@inria.fr
Cc: caml-list@inria.fr
Subject: Re: What will the new syntax be like? (O'Caml + O'Labl)


Jacques Garrigue <Jacques.Garrigue@inria.fr> writes:

> Changes are rather small:
> 
> let foo bar:a zub:b ?qux:c{=10} ?woz:d () =
>   match d with
>   | None -> a + b + c
>   | Some x -> a + b + c + d
> 
> Notice that you need a non-labeled argument after optional ones, due
> to a change in semantics. Optional arguments are now only discarded if
> the function is applied to a non-labeled argument appearing after them
> the function type.
> This change was necessary to resolve some ambiguities, and provide an
> untyped semantics for the language.

Hmm.  This seems like a pain, but I guess I can see the need.  I
always was a little leery of the optional arguments' semantics.

Another thing I've noticed is that non-optional labeled arguments may
have their labels left off.  I wholeheartedly approve of this, since
this was one of my gripes with O'Labl.  (Why should I need to say:
"List.map fun:f l" instead of "List.map f l"?  In many cases, the
label just gets in the way, though it is of help if you're really
going for clarity or you don't know the "standard" order for things
like map.)

The final thing I've noticed in the development version is that I'm
not able to apply labeled arguments out of order.  Is this
intentional, or a side-effect of ongoing work to unify O'Labl and
O'Caml?:

let add :a :b = a + b

# let add :a :b = a + b;;
val add : a:int -> b:int -> int = <fun>
# add b:5 a:3;;
Expecting function has type a:int -> b:int -> int
This argument cannot be applied with label b:

Labels are probably still useful without the potential for
re-ordering, but it does cut down on the utility.  One of the uses I
have for labels is when I have two arguments to a function (say,
List.map), and I want to re-order to make the larger one second.  That
is, it's generally useful for map's first argument to be the function,
but sometimes I want to be able to say:

List.map (short expr of list)
  fun: (long expr
        for the function
        which keeps going)

This follows the natural language model that large complex phrases are
generally not put between a short phrase and the binding phrase--they
reposition to be out of the way.  Having the power to add a short
modifier (fun:) and reorder the expression is a great boon.

> You may like or not the above notation for labels. We had discussions
> here, and the conclusion was that putting spaces around type
> annotations was a good thing anyway...

> It's hard to put that many new features in the language, keeping the
> compatibility with all, and obtain a clean syntax. I must admit.
> However I think that ocaml3 syntax is reasonable enough, at least
> better than olabl's. A second attempt has its advantages.
> 
> By the way, the new version is not yet released, so if you have a
> coherent syntax to propose for the new features, you can propose.

Well, I did some thinking this evening, and here's a summary of where
I went with it.  (I've got what I think is a reasonable and slightly
cleaner proposal near the end, along with a "to my eyes" greatly more
pleasing proposal which would require more parser and lexer changes
(though nothing incompatible).)


The first thought I had was "these optional argument things would be
nicer to read if you could use a keyword to express the optionalness,
rather than a single symbol, and it would also be nice if the equals
sign were more visually bound with the argument".  This led to a
syntax that I feel is too heavy--but I'll show it anyway.  My examples
are based on the following very simple set of functions (in the
current proposed O'Caml 3 syntax):

let div1 num:x den:y = x / y
let div2 :num :den = num / den
let div3 :num ?:den () =
   let v = match den with Some y -> y | None -> 2 in num / y
let div4 num:x ?den:y {= 2} () = x / y

Here's the heavy syntax:

let div1 {| num = x |} {| den = y |} = x / y
let div2 {| num |} {| den |} = num / den
let div3 {| num |} {| optional den |} () = ...
let div4 {| num = x |} {| optional den = y = 2 |} () = x / y

The first problem is seen in div4, where we see that there's a problem
if we wanted to not include the explicit variable binding--I see no
clean way to solve this without an extra special character, which I
was trying to avoid.

The second problem is the weight of {| ... |}, which I thought might
be resolved with:

let div1 {| num = x; den = y |} = ...

and so on.  And a similar syntax for calling.  But this is alien from
the point of view of function application.  So, I dumped this.


The second thing I looked at was the set of "special characters" used
and not used by O'Caml:

Special characters (non-grouping): ~ ` ! @ # $ % ^ & * ' " , . / ? = + \ | -
_
Used by O'Caml (library or special): ! @ # $ % ^ & * ' " , . / = + | - _

O'Caml does use ??, but in a very specific circumstance.  I include $
in the specials list because it's used by camlp4.

This leaves us with: ~ ` ? \

Of these, only ~ is allowed as part of a symbolic ident already.

Which leaves: ` ? \

My proposal is that we should avoid further obfuscating the use of
":".  (Not only is it the type operator, but "::" is cons.  And
there's already confusion between the Haskell and ML families in that
the Haskell family does the exact opposite.  No need to add to the
trouble.)

In order to do that, I first picked "\" as the character of
choice--for two reasons:  First, it's a reasonable "separator"
character, like ":" is.  Second, it's used for absolutely nothing at
the moment.  This leads to the following syntax (keeping default
values the same, and changing only the character used.)

let div1 num\x den\y = x / y
let div2 \num \den = num / den
let div3 \num ?\den () = ...
let div4 num\x ?den\y {= 2} () = x / y

as a further refinement, we can unify the use of \ and ? in the
following way:

let div1 num\x den\y = x / y
let div2 \num \den = num / den
let div3 \num ?den = ...
let div4 num\x den?y {= 2} () = x / y
or
let div4 num\x ?den\y {= 2} () = x / y

this last bit is possible since the O'Caml 3 syntax will not allow
unlabeled optional arguments because of the extra unlabelled argument
constraint you mentioned above.

A final possibility, which I think has great merit but may be hard to
parse, is:

let div1 (\num x) (\den y) = x / y
let div2 \num \den = num / den
let div3 \num ?den () = ...
let div4 (\num x) (?den y = 2) () = x / y

I like this last one, since it allows whitespace between the label and
the expression carrying the value, and allows the = to be used in a
more natural way with the label.  Use follows the same pattern:

div4 (\num 5) (\den 5) ()
div2 (\num 5) (\den 2)
div1 (\den 2) (\num 5)

But the parsing, as I said, could be a pain.


Finally, there's the question of type syntaxes for these.  I propose:

val div1 : num\int -> den\int -> int
val div3 : num\int -> den?int -> unit -> int

or

val div1 : num / int -> den / int -> int
...

(Since / doesn't have to bind the same in types, and "int list" looks
bad as "foo:int list" or "foo\int list", but okay as "foo \ int list")

or

val div1 : \num int -> \den int -> int
val div3 : \num int -> ?den int -> unit -> int

(For the (\label expr), (\label pattern) style.)


Finally, if "\" is rejected for labels, I suggest it be used in place
of "`" on variants, since it's much more distinctive than "`" is:

let (+) x y = match (x,y) with
  | `int x, `int y -> `int (x + y)
  | `int x, `float y -> `float (float x +. y)
  | `float x, `int y -> `float (x +. float y)
  | `float x, `float y -> `float (x +. y)

vs

let (+) x y = match (x,y) with
  | \int x, \int y -> \int (x + y)
  | \int x, \float y -> \float (float x +. y)
  | \float x, \int y -> \float (x +. float y)
  | \float x, \float y -> \float (x +. y)

This is of course incompatible with using \ as the label character.


In summary, I think the style which is most aesthetic is that with
(\label expr), (\label pattern), "\label type" where "\" alternates
with "?" rather than adding to it.

I'm perfectly willing to rework the parser and lexer to use this
style.  I can also work my way through the camltk source, but that
will take longer.


John.




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

end of thread, other threads:[~1999-12-08 19:59 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1999-12-06  3:05 What will the new syntax be like? (O'Caml + O'Labl) John Prevost
1999-12-06 11:05 ` Jacques Garrigue
1999-12-07  7:35   ` John Prevost
1999-12-07 15:36 Don Syme
1999-12-07 18:21 ` Markus Mottl
1999-12-07 18:32 ` skaller

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