为什么在基于 Lisp 的语言中习惯上将许多右括号放在一行上?

发布于 2024-10-05 04:26:43 字数 381 浏览 7 评论 0原文

通常代码看起来像这样:

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

为什么它不这样?

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

:它允许更轻松地添加和删除“另一件事”行(无需删除和重新添加尾随右括号)。您还可以在那个单独的右括号上添加一些注释(例如“;循环结束”)。

当我将使用第二种样式的代码与使用第一种样式的现有代码混合时,情况有多糟糕?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

不念旧人 2024-10-12 04:26:43

在 Lisp 和其他使用 S 表达式作为语法的语言中,括号主要是为了编译器的利益,而布局和缩进(编译器会忽略)则是为了程序员的利益。

因此,不需要在自己的行上放置右括号:精心选择的换行符和缩进足以使结构清晰。

例如,

(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)))

从缩进来看,结构很清晰(对于经验丰富的 Lisp 程序员来说)。将一些右括号放到新行中不会添加任何内容:

(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)
    )
  )

我应该补充一点,几乎所有 Lisp 程序员都使用一个编辑器来显示匹配的括号,执行自动缩进,并提供一个用于直接使用平衡表达式的用户界面。例如,在 Emacs 中,M-( 用于插入新表达式,M-) 用于移过当前表达式的末尾,CMk 用于删除点之后的表达式,等等。

因此,Lisp 程序员永远不必用手计算括号来找出哪些匹配。


Taylor R. Campbell 雄辩地表达了这个理由:

实际的括号字符只是词汇标记,不应赋予其任何意义。 Lisp 程序员不会单独检查括号,或者(阿撒托斯禁止)计算括号的数量;相反,他们查看程序中表达的高层结构,尤其是缩进所呈现的结构。 Lisp 并不是要编写一系列串行指令;而是要编写一系列串行指令。它是通过对各个部分求和来构建复杂的结构。从各个部分组成复杂结构是 Lisp 程序的重点,这一点从 Lisp 代码中应该很明显。在演示文稿中随意放置括号会让 Lisp 程序员感到不舒服,否则他们在大多数情况下都不会看到它们。

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.

箹锭⒈辈孓 2024-10-12 04:26:43

这里有两点需要说明:

  1. 约定本身很重要。坚持使用包裹括号意味着你的代码对其他 lisp 程序员来说更容易阅读,如果你采用这种风格,你还将养成阅读他们的习惯

  2. ) 拆分到自己的行上的优点是在大多数口语者眼中,这实际上并不是优势。如果您使用的是半不错​​的编辑器,它将具有理解平衡表达式的命令,用于在它们之间移动、剪切、粘贴、转置等。所以您不需要

    <前><代码>) ;循环结束

    在 lisp 中,任何超出你需要的内容

    # 循环结束
    

    在一些对空格敏感的语言(如 Python)中

参见例如 http://www.gnu.org/software/emacs/manual/ html_node/emacs/Expressions.html

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

維他命╮ 2024-10-12 04:26:43

简短回答:偏离公认的标准只会疏远潜在的贡献者。没有一种风格比另一种风格更好。

长答案http://blog.fogus。我/2010/08/30/社区标准/

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/

花间憩 2024-10-12 04:26:43

做你喜欢的事!这是你的代码。

也就是说,您最终可能会将它们全部移回来,以便您可以立即在屏幕上显示更多内容。确实,一段时间后您实际上就不再看到括号了。

事实上,情况比这还要糟糕一些。这些天,当我尝试使用心爱的 python 时,感觉我的代码没有括号就没有牢固地绑在一起,我担心它随时可能崩溃。

哎呀,记录几个键盘宏将整个文件从一种风格交换到另一种风格。
(并了解如何使版本控制忽略仅空白的更改。:-)

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. :-)

默嘫て 2024-10-12 04:26:43

如果您使用 Emacs,则需要学习这些。特别是,CMk 使得终止平衡表达式就像终止一行一样简单。再加上平衡括号的良好突出显示,实际上没有必要这样写。

另一方面,将所有这些 ) 单独放在几行上意味着您一次在屏幕上看到的代码会减少,从而使阅读和重构变得更加困难。

如果您不使用 Emacs,您至少应该使用支持这些基本操作的编辑器,否则用 lisp 编码将会很痛苦。

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.

提笔书几行 2024-10-12 04:26:43

节省垂直屏幕(和眼睛)的空间非常重要。

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

醉酒的小男人 2024-10-12 04:26:43

我认为对此的一个很好的答案是提出一个相关的问题:

为什么 Python 程序员不将封闭嵌套的字形放在自己的行上?

现在答案很明显:不存在这样的字形。事实证明,Lisp 中也没有这样的字形:是的,Lisp 阅读器有这些有点烦人的 () 字符需要,但人类不会像这样阅读 Lisp 代码:他们通过缩进和单词来阅读它。

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.

紫﹏色ふ单纯 2024-10-12 04:26:43

括号不是为了可读性而存在的,而是为了计算机而存在的。程序员可以通过查看缩进来了解代码块的结束位置。此外,多个右括号共享一行意味着程序员可以在屏幕上一次查看更多代码。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文