X-Comment1: #############################################################
X-Comment2: # uk.ac.glasgow.cs has changed to uk.ac.glasgow.dcs #
X-Comment3: # If this address does not work please ask your mail #
X-Comment4: # administrator to update your NRS & mailer tables. #
X-Comment5: #############################################################
[Joe, this overrides my earlier, private message...]
I try to keep out of syntax debates, but we need to sort this
out soon and Simon's asked me to delve in :-( We don't have
much time, so please respond as soon as possible if you feel
strongly about this. The final decision rests with Paul, our
benign syntax Czar...
POLEMIC
=======
I feel that making if/let/case bind more tightly than function
application would be a mistake -- for keywords, this form is liable to
reduce program legibility by requiring the reader to scan the input
from left-to-right. While this is easy for a machine to do, it is much
slower for a human reader (who will initially break a text on *strong*
visual symbols, such as operators or parentheses rather than on equally
weighted keywords/identifiers).
For consistency, I would argue that both \ and case should have the
same precedence as let/if. Even though a machine can distinguish
syntactic rules for case from those for let, this requires explicit
recognition of the exception in a human reader/programmer, which slows
perception. To my eye, in the following expression, \ looks much like
an operator (e.g. \\). The -> isn't as strong a clue as it might be in
this particular context:
case x of
C | f \ y -> y
-> x
[equivalent to] case x of
C | f (\ y -> y)
-> x
(I deliberately haven't emphasised keywords in the paragraph above :-)
I have no argument with "let"/"case"/"if"/"\" binding tighter than
operators -- operators have a much greater lexical "weight" than
function application -- there's no danger of losing the keywords
amongst the function arguments -- they always appear either:
i) to the right of an "="
ii) to the right of a "("
iii) to the right of an operator
iv) to the right of a keyword
All of these are strong visual clues which will not be overlooked when
reading a program. Here are some important examples of legal/illegal
expressions under the scheme proposed here.
EXAMPLES
========
LEGAL
-----
1 + if c then 2 else 3 1 + (if c then 2 else 3)
1 + let x = f y in x + x 1 + (let x = f y in x + x)
ILLEGAL
-------
f is it if ic g x y then x else y
g case x of 1 -> 'a'; 2 -> 'b'
I've rewritten the syntax Joe proposed for expressions (eliminating a
couple of minor bugs) to reflect the above suggestions. At Simon's
urging, a third superscript (which makes the syntax explicit, but hard
to read) is replaced by a new meta-rule: "Expressions introduced by a
keyword or '\' extend as far to the right as possible". This catches:
\ x -> x + y
let x = fib 10 in x * x / 2
...
RULES
=====
The syntax includes Joe's fixes for unary minus, and explicit
precedence parsing. His notes on notation follow (edited slightly to
reflect my changes):
In order to avoid a large increase in the number of productions, an
extension to the superscript notation is employed. The syntactic
category exp is now indexed by two superscripts:
A _precedence_level_ from 0 to 9. (10 and 11 are also used
at the top of the precedence hierarchy for function
application.)
An _associativity_, which is a letter n, l, or r, meaning that
the expression is not associated, left-associated, or
right-associated at the given precedence level.
To avoid clutter, we no longer write quantifications for superscript
variables. A precedence level variable is understood to range over 0
to 9, and other variables over all possibilities. We use 'i' for a
precedence variable, and 'a' for associativity. In the report,
variables will be in italics and ground indices in Roman.
----------------------------- SYNTAX RULES BEGIN ----------------------------
exp -> exp(0,n) [ :: [ context => ] atype]
exp(i,n) -> [exp(i+1,n) op(i,n)] exp(i+1,n) (unassoc lev i)
| exp(i,l)
| exp(i,r)
exp(i,l) -> (exp(i,l) | exp(i+1,n)) op(i,l) exp(i+1,n) (left-assoc)
exp(6,l) -> - exp(7,n) (unary -)
exp(i,r) -> exp(i+1,n) op(i,r) (exp(i,r) | exp(i+1,n)) (right-assoc)
exp(10,a) -> \ apat1 ... apatk -> exp
| let { decls [;]} in exp
| if exp then exp else exp
| case exp of { alts [;] }
| fexp
fexp -> fexp aexp
| aexp
---------------------------- SYNTAX RULES END -------------------------------
Kevin