正确评论函数式编程

时间:2010-07-12 17:34:38

标签: functional-programming coding-style comments scheme readability

我一直在学习计划,我才意识到我真的不知道如何正确评论我的功能方案代码。我知道如何添加评论当然 - 您添加;并在其后添加评论。我的问题是我应该在评论中添加什么,我应该在哪里评论其他程序员阅读我的代码的最大可读性和可理解性?

这是我写的代码片段。这是一个名为display-n的函数。它可以使用任意数量的参数调用,并按照提供的顺序将每个参数输出到屏幕。

(define display-n
  (lambda nums
    (letrec ((display-n-inner 
              (lambda (nums)
                (display (car nums))
                (if (not (equal? (cdr nums) (quote ()))
                    (display-n-inner (cdr nums))))))
      (display-n-inner nums))))

修改:改进了标签,并将'()替换为(quote ()),以避免格式化。

我只是不确定如何/在哪里添加评论以使其更容易理解。我看到的一些方案代码在顶部有注释,如果你想使用代码,这很好,但是如果你想理解/修改代码则无用。

另外 - 我该如何评论宏?

4 个答案:

答案 0 :(得分:6)

Lisp评论的常见风格是

  • 四个分号,用于对文件的整个子部分进行评论。
  • 用于引入单个程序的三个分号。
  • 两行用于描述以下行中的表达式/过程定义。
  • 一个分号用于结束评论。

程序概述注释应该遵循RnRS文档的样式,所以只需按原样添加注释,看起来就像

;;; Procedure: display-n NUM ...
;; Output each argument to the screen in the order they are provided.
(define 
  display-n (lambda nums
              (letrec ((display-n-inner (lambda (nums)
                                          (display (car nums))
                                          (if (not (equal? (cdr nums) '()))
                                              (display-n-inner (cdr nums))))))
                (display-n-inner nums))))

N.B。我不会在整个过程描述中使用三个分号,因为它会搞砸Emacs中的fill-paragraph。


现在关于代码,我会抛弃整个define-variable-as-a-lambda的东西。是的,我认为这是定义一个函数的“最纯粹的”方式,并且它与定义过程的良好一致性是LET和其他过程的结果,但是有一个合成糖的原因,它是为了让事情变得更多可读。对于LETREC来说也是如此 - 只需使用内部DEFINE,这是相同的,但更具可读性。

DISPLAY-N-INNER的参数被称为NUMS并不是什么大不了的事,因为程序太短而且DISPLAY-N无论如何都直接将它的NUMS直接交给它。不过,“DISPLAY-N-INNER”是一个蹩脚的名字。你会给它一些具有更多语义含义的东西,或给它一个简单的名字,如“ITER”或“LOOP”。

现在关于程序的逻辑。首先,(equal? (cdr nums) '())是愚蠢的,并且更好(null? (cdr nums))。实际上,当您在整个列表上操作时,最好使基本案例测试列表本身而不是其CDR是否为空。这样,如果你没有传递任何参数,程序就不会出错(除非你希望它这样做,但我认为如果没有任何东西,DISPLAY-N更有意义什么都没有)。此外,您应该测试是否停止该过程,而不是是否继续:

(define (display-n . nums)
  (define (iter nums)
    (if (null? nums)
        #t  ; It doesn't matter what it returns.
        (begin (display (car nums))
               (iter (cdr nums)))))
  (iter nums))

但是对于所有这些,我会说程序本身并不是完成任务的最佳方法,因为它过于关注遍历列表的细节。相反,你会使用更抽象的FOR-EACH方法来完成工作。

(define (display-n . nums)
  (for-each display nums))

通过这种方式,他可以理解FOR-EACH将显示NUMS的每个元素,而不是程序的读者陷入CAR和CDR的细节中。

答案 1 :(得分:4)

一些随机记录:

  • 传统上,Scheme和Lisp代码使用;;;来发表评论,;;用于代码中的评论,;用于评论与代码相同的行评论。 Emacs对此有所支持,对待这些中的每一个都有所不同。但特别是在Scheme方面,这已不再像以前那样流行,但;;;之间的差异仍然很常见。

  • 大多数现代计划采用了新的评论:theres:

    • #|...|#用于块注释 - 对于评论整个文件的长文本非常有用。
    • #;<expr>是一个注释,它使实现忽略表达式,这对调试非常有用。
  • 至于要写的内容的实际内容,与其他任何语言都没有什么不同,除了通过更多功能方法,您通常可以选择如何布局代码。它还使编写较小的功能更加方便,这些功能组合成更大的功能 - 这也改变了文档样式,因为许多这样的小功能将是“自我记录”(因为它们易于阅读和非常他们的工作方式很明显。

  • 我讨厌听起来像一个破纪录,但我仍然认为你应该花一些时间与HtDP。它在设计方法中鼓励的一件事是首先编写示例,然后编写文档,然后将其扩展为实际代码。此外,这个配方为您提供了一组具有非常标准的注释的代码:输入/输出类型,目的语句,有关如何在必要时实现该功能的一些文档,以及这些示例可以被视为另一种文档(这将转向“真实”代码中的注释代码。 (还有其他书籍在文档中采取了类似的立场。)

  • 最后,记录宏与记录任何其他代码没有什么不同。唯一可能与评论中所写内容完全不同的是:您不会描述某些函数正在执行的操作,而是倾向于描述它扩展的代码,因此评论也更多地关于元水平。宏的一个常见方法是最小化宏内部的工作 - 只需要在该级别需要的内容(例如,在(lambda () ...)中包装表达式),并将实际实现留给函数。这也有助于记录,因为这两个相关的部分将独立地评论宏的扩展方式和运行方式。

答案 2 :(得分:2)

我遵循类似于此处发布的方法:

http://www.cc.gatech.edu/computing/classes/cs2360/ghall/style/commenting.html

注意:这适用于Common Lisp。

具体做法是:

" Four Semicolons(;;;;)
...denote a sub heading in the file...

Three Semicolons(;;;)
...denote a description of the succeeding function, macro, or
variable definition...
[I usually just most of the description into the "docstring"
  of the function or variable.] 


 Two Semicolons(;;)
 ...denote a description of the succeeding expression...

 One Semicolon(;)
 ...denotes an in-line comment that explains a particular element
    of the expression on that line... Brevity is important for
    inline comments"

答案 3 :(得分:0)

我认为一个好的起点是将你的一句话描述为函数的作用

  

可以使用任意数量的参数调用它,并按照提供的顺序将每个参数输出到屏幕。

作为评论的开头。

我不是特别熟悉计划,所以我不能评论(:-)是否有额外的逐行评论解释函数如何实现该结果的机制将根据正常的方案风格预期(但我怀疑不是。)