Path: utzoo!utgpu!jarvis.csri.toronto.edu!rutgers!tut.cis.ohio-state.edu!ucbvax!hplabs!otter!sfk From: sfk@otter.hpl.hp.com (Stephen Knight) Newsgroups: comp.lang.lisp Subject: Re: Re: Code as data (replies to comments). Message-ID: <1350020@otter.hpl.hp.com> Date: 9 Jun 89 19:44:02 GMT References: <1057@syma.sussex.ac.uk> Organization: Hewlett-Packard Laboratories, Bristol, UK. Lines: 118 The discussion on the merits and demerits of Lisp syntax touched a couple of interesting points that I'd like to comment on. 1. Code as Data, Macros and So On Macros in languages such as C or Pop11 are quite different beasts to that supported in Lisp(s). Lisp does not make any distinction between parse and lexis so that macro processing in Lisp is parse tree procesing. In other languages, macro processing is typically performed at the level of a flat, unstructured input stream. It should be plain that this makes Lisp macros very much more powerful and useful (when used in a disciplined fashion). However, the lack of a distinct lexis phase, the read-table being a poor substitute, rather limits the syntactic flexibility of macros. It's usually possible to achieve the effects required by abusing the read-table but a separate phase of chunking the input stream into tokens (as in Pop11) would be beneficial. To perform the kind of parse-tree processing that Lisp does, it is clear that some kind of data-representation of code is required. The questions that are raised are (a) is it useful to show this relationship in the syntax? (b) if it is, does this mean that some kind of prefix syntax (or variation) is inevitable? I cannot convince myself that it is valuable to expose the parse-tree representation in the syntax. It is convenient in some sense, because only one thing has to be learnt. It is inconvenient in another sense, because the syntactic presentation of programs should be geared to people rather than an internal representation. However, even if one believes that the price is right, there is no reason to take the s-expression route. A good counter-example is provided by the (DEC-10) syntax for Prolog. Prolog programs are also Prolog data structures but the syntax is attractive. The solution in Prolog is to arrange for the syntactic properties of the data constructors to be the same as the syntax of the program. 2. Why Don't Lispers Use PreProcessors? A earlier comment suggested that the general disinterest in preprocessors reflected satisfaction with Lisp's syntax. That story doesn't match my own. I am inclined to think that the main reason for disinterest is that the benefits of the superior syntax are outweighed by non-language disadvantages. Firstly, any program I deliver using this syntax has even more development environment captured (yuk). Next, the error reporting typically exposes teh fact I am using a preprocessor. Some of the preprocessors are based on the Lisp reader so that one gets all the disadvantages. There are no standard textbooks I can read to learn this new syntax. When I deliver a program to the person who has the unenviable task of maintenance, they are unlikely to know this new syntax. 3. Is Lisp Syntax Perfect? As far as I am concerned, any language which makes me write (+ x (* y z)) has made a rather dubious compromise. None of the respondents to the original posting could find any fault with the syntax! Outside the Lisp community, the syntax is widely considered to be a laughing matter. Surely Lispers generally have a more balanced view of the compromises made in the syntactic design. One doesn't have to go very far before noticing some very strange things about Lisp syntax. (These comments are a bit loose because different Lisps have different syntactic details. Forgive.) Here follows a non-exhaustive list of funnies in Lisp syntax. You can skip this if you've got the idea. For example, the basic form of a function application is (f x y). However, this shape can occur in many places with radically different meaning e.g. a let binding. Far more logical, I believe, would be to have a key word (e.g. apply) which would notify the reader that this was an apply node. This would have an additional benefit that should the language be extended with new syntactic forms (special forms) there would be no name clash. Of course, this would be clumsy and verbose to write (and read) points out that syntax is not just a matter of taste. The idea of an 'apply special form' is good for the machine but bad for people. Another example would be the overloading of #. Why have #'(lambda ...) at all? Surely having (lambda ...) denote a function is a perfectly simple concept that fits well with the idea of a parse tree, and so on. Why denote true and false by #T and #F? Why bother to denote them at all? One could simply use variables "true", "false", and "nil". Why clutter up the syntax so pointlessly? Why denote vectors with #( ... )? Why not use different brackets? How is #( ... ) any more tightly bound to the parse tree than, say, { ... } (as in Pop11). Indeed, why write lists as (list E1 .. En) rather than, say, [E1 ... En]? After all, if one can have #( ... ) for vectors, why shouldn't lists have equal priviledge? On the topic of macros, there is actually a need to write in a disciplined fashion. One might be tempted to think that (f E1 ... En) means apply f to the results of E1 to En. However, if "f" is a macro, there is no obligation for it to evaluate E1 to En, at all. It might quote bits of them, evaluate bits of them, or anything at all. Furthermore, any errors reported will be described in terms of the resultant code -- which you may well be completely unaware of. Why are atoms quoted with a single quote at the start? Why not have a quote at the end as well? Most people are used to quotes matching. Brackets match, after all. Why not quotes? String quotes match (of course). 4. Summary As far as I can see, these points (and endless others) add up as follows. Lisp's syntax is a compromise between uniformity and readability. There are many inconsistencies which reflect the growth of Lisp's syntax away from the machine and towards the user. In order to satisfy both the desires of structural uniformity (for the machine) and readability (for the human) a distinction between concrete syntax and abstract syntax is valuable. Almost all language designers have come to this conclusion. Lisp's syntax remains an anachronism that inhibits the acceptance of the language in many contexts where its superior expressive power would be appropriate.