Lisp Parentheses

Solution 1:

LISP IDE environments tend to balance parentheses automatically and manage indents based on nesting level. Sample 2 does not bring any advantages in those situations.

In the C/FORTRAN/Pascal heritage, you tend to emphasize sequencing over nesting (code parse trees are shallower and wider). End of scope is a more significant event in your code: hence emphasis has been and still to some extent is more important.

Solution 2:

For experienced Lisp users, the nesting level is more important than finding closing parentheses. Putting closing parentheses on their own lines does not really help with nesting levels.

The basic idea is that the parentheses are directly AROUND their contents.

(a)

and not

(a
)

What follows is this:

(defun foo (bar)
  (foo (bar (baz
              ...
             )
         ...
        )
    ...
   )
 )

vs.

(defun foo (bar)
  (foo (bar (baz ...) ...) ...))

One of the basic ideas when editing Lisp text is, that you can select a list by (double-) clicking on the parentheses (or by using a key command when the cursor is inside the expression or on the parentheses). Then you can cut/copy the expression and paste it into another position in some other function. Next step is to select the other function and re-indent the function. Done. There is no need to remove or introduce new lines for for closing parentheses. Just paste and re-indent. It just fits in. Otherwise you would either waste time formatting the code, or you would need to re-format the code with some editor tool (so that closing parentheses are on their own lines. Most of the time it that would create additional work and hinders moving code around.

There is one occasion where experienced Lispers would sometime write closing parentheses on their own line:

(defvar *persons*
   (list (make-person "fred")
         (make-person "jane")
         (make-person "susan")
         ))

Here it indicates that new persons can be added. Place the cursor directly before the second closing parentheses on the last line, press c-o (open line), add the clause and indent the parentheses that they are aligned again. This saves the 'trouble' to find the right parentheses and then press return, when all parentheses are closed on one line.

Solution 3:

Because there is no need whatsoever to line up closing parens. It doesn't add anything semantically. To know how many to close, most Lispers use a good editor, such as Emacs, that matches parens to closing parens and hence makes the task trivial.

In Python, there are no closing parens or end keywords at all, and Pythonistas live just fine.

Solution 4:

After a while with Lisp you don't notice the parentheses any longer, so your example two comes across as having a bunch of unnecessary whitespace in the end of it. More specifically, most lispers use an editor that is aware of parentheses and takes care of closing the forms correctly, so you as the developer don't need to match opening and closing parentheses like you do in e.g. C.

As for whether the last form should be

(* n (factorial (- n 1)))

or

(* n
   (factorial (- n 1)))

that mostly comes down to personal preference and how much stuff is going on in the code (In this case I'd prefer the former just because there is so little happening in the code).

Solution 5:

Why do C programmers write things like:

((a && b) || (c && d))

instead of

((a && b) || (c && d
             )
)

Wouldn't #2 be easier to read? :)

Seriously, though, the bunched up closing style works well for other languages, too.

#include <stdlib.h>
#include <stdio.h>

int main(void)
{ int i, j, k;
  for (i = 0; i < 1000; i++)
  { for (j = 0; j < 1000; j++)
    { for (k = 0; k < 1000; k++)
      { if (i * i + j * j == k * k)
        { printf("%d, %d, %d\n", i, j, k); } } } }
  return 0; }

After a while, you don't "see" the braces, just the structure given by the indentation. if/else looks like this:

if (cond)
{ stmt;
  stmt; }
else
{ stmt; }

switch:

switch (expr)
{ case '3':
    stmt;
    break;
  case '4':
  { stmt;
    break; } }

structs:

struct foo
{ int x;
  struct bar
  { int y; };
  union u
  { int a, b;
    char c; }; };