Improving Lisp Syntax Is Harder Than It Looks
Posted by Peter on March 17, 2006
One of the biggest complaints I hear (by biggest I mean most often) is that Lisp syntax is ugly. One common issue is that people from a mathematical background would like to invoke functions as
name(parameters) instead of
(name parameters). This kind of change wouldn’t be hard to make, and yet few lisp versions, except some of the very early variants and TwinLisp implement it.
The real motivation for leaving Lisp syntax as it is comes from macros. Under the current syntax macros can treat the code as a series of nested lists, which makes it easy to write intuitive looking macro expansions, for example if a macro expands into
'(display "text") it is pretty obvious what it does. Although in theory you could keep this macro system with a new Lisp syntax it would look strange, and basically force users of the language to know both the old syntax and the new syntax. Thus we would expect the macros to read in the function call under this kind of syntax as some new kind of object, with one operation returning the function symbol, and another operation returning the list of parameters. Thus a macro expansion would have to look something like this:
build-call('display '("text")). Not only does this expansion fail to visually look the same it also is much more complicated. One could try to get around this by altering the quasiquote operator, as in TwinLisp, so that the expansion becomes
`display("text"), but then we have sacrificed the simplicity of the quasiquote, which no longer operates on lists. No matter how you solve the problem you end up in a bit of a bind.
Another disadvantage to this change of syntax is that it makes functional programming much more odd looking. Lets say you have a list containing functions and you want to call the first one. In Scheme you write
((car lst) params) and in Common Lisp
(funcall (car lst) params). However in our new syntax it looks like:
funcall(car(lst) (params)). Neither of these is very elegant, and it only gets worse if that call in turn returns a function, which would look like:
funcall(funcall(car(lst) (params)) (params2)).
So changing lisp’s syntax, at least to make it more conventional in terms of function calls, is not really a win, although the average cases look slightly more “normal” more complicated operations become more convoluted. Of course that doesn’t necessarily mean that we can’t improve Lisp’s syntax at all, in a future post I will discuss the benefits and disadvantages of adding a block structure to Lisp (as proposed in Arc, TwinLisp, ect).