Well it’s impossible to remove all of the parentheses in Lisp, but I can think of several methods to eliminate the bulk of them. One alternative to parentheses is being sensitive to white space, in a way that is reminiscent of Python. The simple description is as follows: each line automatically has an opening parenthesis added before it, and a closing parenthesis added after it, except under the following circumstances: if the following line has one extra level of indentation omit the closing parenthesis. If the line in question is indented two or more levels beyond the previous line add an extra opening parenthesis for every new level of indentation beyond the first. If the line following the line in question is less indented than the line we are examining add an extra closing parenthesis for each level less. (the end of the file should be treated as a line with 0 indentation of course)
Let’s apply these rules to some simple cases:
A cond statement of the following nature:
(cond
((< x -1) (* x x))
((> x 1) (* x x))
((< x 0) (sqrt (abs x)))
(else (sqrt x)))
would become:
cond
(< x -1) (* x x)
(> x 1) (* x x)
(< x 0) (sqrt (abs x))
else (sqrt x)
if we are willing to take up some more lines it could also become:
cond
(< x -1)
* x x
(> x 1)
* x x
(< x 0)
sqrt (abs x)
else
sqrt x
Admittedly this expansion looks rather verbose for such a simple cond statement, but if the cond was more complex, and had more instructions in each branch, it would not be too much of an expansion, because it is likely the programmer would have already indented it in this fashion.
Now consider the let statement:
(let
((a (+ 1 v)) (b (car z)) (c (avg 8 3 w)) (d w))
(body-goes-here))
This statement could be written as:
let
(a (+ 1 v)) (b (car z)) (c (avg 8 3 w)) (d w)
body-goes-here
or as:
let
a (+ 1 v)
b (car z)
c (avg 8 3 w)
d w
body-goes-here
So far everything looks pretty nice, but there are a few problems with this method. For example: consider the case where programmers break a function containing many, possibly complicated, arguments onto several lines:
(my-large-function
(car (cdr y))
(lambda (x) (/ x 2))
my-list)
we want to break it up like so:
my-large-function
car (cdr y)
lambda (x) (/ x 2)
my-list
but unfortunately the rules we have laid out dictate the my-list should be wrapped with parentheses, and thus will be called like a function. This can also be a problem when you want to put more than one function call on a single line, for example:
(lambda (x)
(display x) (newline)
(* x 42))
is not properly translated as:
lambda (x)
(display x) (newline)
* x 42
since the result of (display x) is not a function to be applied to the result of (newline).
There are several ways to overcome this, for example using values (in an ideal world, where it worked like you expected it to) and begin. However a simpler solution is to simply add a special prefix the language that when encountered before a line instructs the compiler/reader to add one less pair of parentheses around the line. I would suggest the \ character, since it has been used in other contexts as an escape character. Our examples then would be written (correctly) as follows:
my-large-function
car (cdr y)
lambda (x) (/ x 2)
\ my-list
lambda (x)
\ (display x) (newline)
* x 42
Note: \ is not notation for the continuation of a line.
Well, it’s something to think about at least. I know some people will object for the same reasons they do to Python’s white space sensitivity, but consider this before you dismiss it out of hand: one of the biggest barriers to the adoption of Lisp is that the sheer bulk of parentheses can be intimidating, and a method such as this would hide the majority of them, especially the large mass of closing parenthesis that seems to end every complicated function.
As you may know I plan on experimenting with my own Scheme variant soon, and this is one of the ideas I think I will try out in it (as a compiler option of course, not a mandate), unless I hear a good reason not to.