【问题标题】:Lisp commenting conventionLisp 注释约定
【发布时间】:2011-09-15 23:00:11
【问题描述】:

关于不同类型的 cmets 使用多少分号(以及不同数量的分号的缩进级别应该是多少),Lisp 的约定是什么?

此外,关于何时使用分号 cmets 以及何时使用 #|multiline comments|# 是否有任何约定(假设它们存在并存在于多个实现中)?

【问题讨论】:

标签: comments lisp common-lisp conventions


【解决方案1】:

令人讨厌的是,人们在引用约定时却没有解释在行尾 cmets 中使用双分号有什么问题。

在所谓的“边距”(行尾)cmets 中使用双分号本身并没有错。如果您想在同一个块中拥有边距 cmets 和常规 cmets,这可能会成为一个问题,例如:

   (defn foo []
      (bar) ;; yup, bar
      ;; let's now do a zap
      (zap))

因此,如果您使用 Emacs 的 fill-paragraph 功能 - 它会自动对齐这两个 cmets,就好像它们是单个语句一样。

   (defn foo []
      (bar) ;; yup, bar
            ;; let's now do a zap
      (zap))

这可能不是您想要的。因此,如果改用单个分号:

   (defn foo []
      (bar) ; yup, bar
      ;; let's now do a zap
      (zap))

它将按预期保持。因此,与其一遍又一遍地解释这一点,我猜人们只是制定了一个规则 - 使用单个分号作为边距 cmets

【讨论】:

    【解决方案2】:

    多行 cmets #| |# 通常用于注释掉大量的 Lisp 代码或示例代码。由于某些 Emacs 实现似乎无法解析它们,因此有些使用 #|| ||# 代替。

    有关分号的使用,请参阅 Guy L. Steele Jr. 所著的 Common Lisp the Language(第 348 页)一书中的注释示例,1984 年,Digital Press,作者:

    ;;;; COMMENT-EXAMPLE function. 
    ;;; This function is useless except to demonstrate comments. 
    ;;; (Actually, this example is much too cluttered with them.) 
    
    (defun comment-example (x y)      ;X is anything; Y is an a-list. 
      (cond ((listp x) x)             ;If X is a list, use that. 
            ;; X is now not a list.  There are two other cases. 
            ((symbolp x) 
            ;; Look up a symbol in the a-list. 
            (cdr (assoc x y)))        ;Remember, (cdr nil) is nil. 
            ;; Do this when all else fails: 
            (t (cons x                ;Add x to a default list. 
                     '((lisp t)       ;LISP is okay. 
                       (fortran nil)  ;FORTRAN is not. 
                       (pl/i -500)    ;Note that you can put comments in 
                       (ada .001)     ; "data" as well as in "programs". 
                       ;; COBOL?? 
                       (teco -1.0e9))))))
    

    在本例中,cmets 可能以一到四个分号开头。

    • 单分号 cmets 都对齐到右侧的同一列;通常每个注释只涉及它旁边的代码。有时一个注释足够长到占据两三行;在这种情况下,通常会将注释的连续行缩进一个空格(在分号之后)。

    • 双分号 cmets 与代码的缩进级别对齐。空格通常跟在两个分号后面。此类 cmets 通常描述程序在该点的状态或注释后面的代码段。

    • 三分号 cmets 与左边距对齐。它们通常记录整个程序或大型代码块。

    • 四分号 cmets 通常表示整个程序或大代码块的标题。

    【讨论】:

      【解决方案3】:

      在 Common Lisp 中:

      ;;;; At the top of source files
      
      ;;; Comments at the beginning of the line
      
      (defun test (a &optional b)
        ;; Commends indented along with code
        (do-something a)                      ; Comments indented at column 40, or the last
        (do-something-else b))                ; column + 1 space if line exceeds 38 columns
      

      注意:Emacs 不能很好地字体化 #| |#,但正如 Rainer 在 cmets 中建议的那样,尝试改用 #|| ||#

      我想说没有使用这个规则的规则,但我认为注释大量代码或插入一些长描述会更快,因为分号会妨碍编辑,比如巨大的 BNF 列表或之类的。

      有一个巧妙的技巧可以禁用代码,即在表达式前面加上#+(or):

      (defun test (a &optional b)
        #+(or)
        (do-something a)
        (do-something-else b))
      

      注意:#+nil 通常也可以使用,除非您碰巧有 nil:nil 功能。 #+(or) 的优势在于,您可以通过将其注释掉或将其更改为 #+(and) 来轻松编辑它,或者实际包含一组您真正希望读取该表达式的功能。

      当您运行 Lisp 时,SLIME 通过将 (do-something a) 的形式字体化为注释来提供帮助。

      除了 Common Lisp 特有的注释语法和技巧,例如 #| |##+(or) 或更常见的 #+nil,我相信分号规则在其他 lisp 中也被广泛采用。


      这是the specification 的摘录,请注意当前在单个分号方面的做法有何不同:

      2.4.4.2 关于分号样式的注意事项

      一些文本编辑器会根据开始注释的分号数来假设所需的缩进。以下样式约定是常见的,但绝不是通用的。

      2.4.4.2.1 单分号的使用

      以单个分号开头的评论都对齐到右侧的同一列(有时称为“评论列”)。这种注释的文本通常只适用于它出现的行。偶尔两个或三个包含一个句子;这有时通过缩进除第一个以外的所有内容加上一个额外的空格(在分号之后)来表示。

      2.4.4.2.2 双分号的使用

      以双分号开头的注释都对齐到相同的缩进级别,因为表单在代码中的相同位置。此类注释的文本通常描述了该注释出现处的程序状态、注释之后的代码,或两者兼而有之。

      2.4.4.2.3 三重分号的使用

      以三个分号开头的评论都对齐到左边距。通常在定义或定义集之前使用它们,而不是在定义中。

      2.4.4.2.4 四分号的使用

      以四分号开头的注释都与左边距对齐,通常只包含一小段文本,用作后面代码的标题,可能会在程序的页眉或页脚中使用准备代码以作为硬拷贝文档呈现。

      2.4.4.2.5 分号样式示例

      ;;;; Math Utilities
      
      ;;; FIB computes the the Fibonacci function in the traditional
      ;;; recursive way.
      
      (defun fib (n)
        (check-type n integer)
        ;; At this point we're sure we have an integer argument.
        ;; Now we can get down to some serious computation.
        (cond ((< n 0)
               ;; Hey, this is just supposed to be a simple example.
               ;; Did you really expect me to handle the general case?
               (error "FIB got ~D as an argument." n))
              ((< n 2) n)             ;fib[0]=0 and fib[1]=1
              ;; The cheap cases didn't work.
              ;; Nothing more to do but recurse.
              (t (+ (fib (- n 1))     ;The traditional formula
                    (fib (- n 2)))))) ; is fib[n-1]+fib[n-2].
      

      【讨论】:

      • 您可以使用任何不为#+nil 部分指定功能的词,例如#+todo, #+alternative-version, #+perhaps-needed-later.
      • 如果 Emacs 的 #| 出现问题|# 使用 #|| ||# .
      • #+nil 注释掉代码会侮辱 NIL(Lisp 的新实现)的实现者,所以我建议 #+|| #+\;或类似的。
      【解决方案4】:

      Common Lisp 风格的标准参考,包括注释约定,是 Peter Norvig 和 Kent Pitman 的 Tutorial on Good Lisp Programming Style

      【讨论】:

        【解决方案5】:

        这里不再描述它,而是看一下this page。它是关于 Emacs Lisp,但所有 lisp(和方案)的约定都是相同的。

        【讨论】:

        • 谢谢! (为什么 cmets 需要最少字符数?)
        • @Eli Barzilay:他指的是 Stackoverflow 评论框。 :)
        • @Eli:我才明白你为什么感到困惑。
        猜你喜欢
        • 2023-03-03
        • 2017-06-16
        • 2011-04-05
        • 2010-11-02
        • 2011-09-13
        • 2011-12-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多