-->

Why is it customary to put many closing parenthese

2020-05-29 15:37发布

问题:

Usually code looks like this:

(one-thing
    (another-thing arg1 (f arg5 r))
    (another-thing arg1 (f arg5 r)))

Why doesn't it like this?:

(one-thing
    (another-thing arg1 (f arg5 r))
    (another-thing arg1 (f arg5 r))
)

It allows adding and removing "another-thing" lines more easily (without removing and re-adding trailing closing parenthesis). Also you can put a some comment on that lone closing parenthesis (such as "; end of the loop").

How bad is it when I mix by code that uses the second style with existing code that uses the first style?

回答1:

There are two points to be made here:

  1. Conventions are important in themselves. Sticking to wrapped parens means your code is more readable by other lisp programmers, and if you adopt this style you will also develop practice at reading theirs

  2. The advantages of splitting )s onto their own lines are not actually advantages in the eyes of most lispers. If you are using a half-decent editor it will have commands that understand balanced expressions, for moving across them, cutting, pasting, transposing, etc. So you don't need

    )  ; end of the loop
    

    in lisp any more than you need

    # end of the loop
    

    in some whitespace-sensitive language like Python

See e.g. http://www.gnu.org/software/emacs/manual/html_node/emacs/Expressions.html



回答2:

In Lisp and other languages that use S-expressions for syntax, the parentheses are primarily for the benefit of the compiler, while layout and indentation (which are ignored by the compiler) are for the benefit of programmers.

So there is no need to put closing parentheses on their own lines: well-chosen line breaks and indentation will be sufficient to make the structure clear.

For example,

(defun clone-indirect-buffer-other-window (newname display-flag &optional norecord)
  "Like `clone-indirect-buffer' but display in another window."
  (interactive
   (progn
     (if (get major-mode 'no-clone-indirect)
         (error "Cannot indirectly clone a buffer in %s mode" mode-name))
     (list (if current-prefix-arg
               (read-buffer "Name of indirect buffer: " (current-buffer)))
           t)))
  (let ((pop-up-windows t))
    (clone-indirect-buffer newname display-flag norecord)))

The structure is clear (to a moderately experienced Lisp programmer) from the indentation. Nothing would be added by bringing some of the closing parentheses down onto new lines:

(defun clone-indirect-buffer-other-window (newname display-flag &optional norecord)
  "Like `clone-indirect-buffer' but display in another window."
  (interactive
   (progn
     (if (get major-mode 'no-clone-indirect)
         (error "Cannot indirectly clone a buffer in %s mode" mode-name)
       )
     (list (if current-prefix-arg
               (read-buffer "Name of indirect buffer: " (current-buffer))
             )
           t)
     )
   )
  (let ((pop-up-windows t))
    (clone-indirect-buffer newname display-flag norecord)
    )
  )

I should add that nearly all Lisp programmers use an editor that displays matching parentheses, performs automatic indentation, and provides a user interface for working direcly with balanced expressions. In Emacs, for example, there's M-( for inserting a new expression, M-) for moving past the end of the current expression, C-M-k for deleting the expression after point, and so on.

So Lisp programmers never have to count parentheses by hand in order to figure out which ones match.


Taylor R. Campbell eloquently expresses this rationale:

The actual bracket characters are simply lexical tokens to which little significance should be assigned. Lisp programmers do not examine the brackets individually, or, Azathoth forbid, count brackets; instead they view the higher-level structures expressed in the program, especially as presented by the indentation. Lisp is not about writing a sequence of serial instructions; it is about building complex structures by summing parts. The composition of complex structures from parts is the focus of Lisp programs, and it should be readily apparent from the Lisp code. Placing brackets haphazardly about the presentation is jarring to a Lisp programmer, who otherwise would not even have seen them for the most part.



回答3:

Short answer: Deviating from recognized standards only serves to alienate potential contributors. No one style is optimally better than another.

Long answer: http://blog.fogus.me/2010/08/30/community-standards/



回答4:

Do what you like! It's your code.

That said, you'll probably eventually move them all back so that you can get more stuff on the screen at once. It really is true that you effectively stop seeing the brackets after a while.

Actually, it's a bit worse than that. These days when I try to use beloved python, it feels like my code isn't securely tied together without its brackets and I worry that it might fall apart at any moment.

Hell, record a couple of keyboard macros to swap the whole file from one style to the other. (And learn how to make your version control ignore whitespace-only changes. :-)



回答5:

If you're using Emacs, you need to learn these. In particular, C-M-k makes killing a balanced expression just as easy as killing a line. Couple that with good highlighting of balanced parentheses, and there's really no need to write things this way.

On the other hand, having all those )s on lines by themselves means that you see less of your code on the screen at once, making it harder to read and refactor.

If you're not using Emacs, you should at least be using an editor that supports those basic operations, or coding in lisp is going to be a pain.



回答6:

Saving vertical screen (and eye) real-estate space is important.



回答7:

I think a good answer to this is ask a related question:

why don't Python programmers put the glyphs that close nesting on their own lines?

And the answer now is obvious: there are no such glyphs. And it turns out that there are no such glyphs in Lisp either: yes, there are these mildly annoying ( and ) characters that the Lisp reader needs, but human beings do not read Lisp code like this: they read it by indentation and words.



回答8:

The parentheses aren't there for readability, they are there for the computer. The programmer can see where the block of code ends by looking at the indents. Furthermore, having multiple closing parentheses share a line means the programmer can view more code at once on the screen.