函数式编程的正确注释

发布于 2024-09-10 05:33:16 字数 729 浏览 4 评论 0原文

我一直在学习方案,我刚刚意识到我真的不知道如何正确注释我的功能方案代码。我当然知道如何添加评论 - 您添加一个 ; 并将您的评论放在它后面。我的问题是我应该在注释中添加什么内容,以及我应该在哪里注释才能为其他程序员阅读我的代码提供最大的可读性和可理解性?

这是我写的代码片段。这是一个名为 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 ()) 以避免搞乱格式。

我只是不确定如何/在哪里添加注释以使其更容易理解。我见过的一些方案代码在顶部只有注释,如果您想使用代码,这很好,但如果您想理解/修改它,则没有帮助。

另外 - 我应该如何评论宏?

I've been learning scheme, and I just realized that I don't really know how to properly comment my functional scheme code. I know how to add a comment of course - you add a ; and put your comment after it. My question is what should I put in my comments, and where should I comment for maximum readability and comprehensability for other programmers reading my code?

Here's a code snippet I wrote. It's a function called display-n. It can be called with any number of arguments and outputs each argument to the screen in the order that they are provided.

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

Edit: Improved tabbing and replaced '() with (quote ()) to avoid SO messing up the formatting.

I'm just not sure how/where to add comments to make it more understandable. Some scheme code I've seen just has comments at the top, which is great if you want to use the code, but not helpful if you want to understand/modify it.

Also - how should I comment macros?

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

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

发布评论

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

评论(4

就是爱搞怪 2024-09-17 05:33:16

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 中的填充段落。


现在关于代码,我会放弃整个定义变量作为 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))

这样,程序的读者就不会陷入 CAR 和 CDR 的细节中,而只需了解 FOR-EACH 将显示 NUMS 的每个元素。

The common style for Lisp comments is

  • Four semicolons for commentary on a whole subsection of a file.
  • Three semicolons for introducing a single procedure.
  • Two semicolons for a description of the expression/procedure definition on the following line.
  • One semicolon for an endline comment.

Procedure overview comments should probably follow the style of RnRS documens, so to just add comments to your procedure as-is, would look something like

;;; 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. I don't use three semicolons for the whole procedure description, since it screws up fill-paragraph in Emacs.


Now about the code, I would ditch the whole define-variable-as-a-lambda thing. Yes, I get that this is the "purest" way to define a function, and it makes for a nice consistency with defining procedures are the results of LETs and other procedures, but there's a reason for syntactic sugar, and it's to make things more readable. Same for the LETREC—just use an internal DEFINE, which is the same thing but more readable.

It's not a huge deal that DISPLAY-N-INNER's parameter is called NUMS, since the procedure's so short and DISPLAY-N just hands its NUMS straight to it anyways. "DISPLAY-N-INNER" is sort of a lame name, though. You would give it something with more semantic meaning, or give it a simple name like "ITER" or "LOOP".

Now about the logic of the procedure. First, (equal? (cdr nums) '()) is silly, and is better as (null? (cdr nums)). Actually, when you are operating over an entire list, it's best to make the base case a test of whether the list itself, and not its CDR, is empty. This way the procedure won't error if you pass it no arguments (unless you want it to do that, but I think it makes more sense for DISPLAY-N to do nothing if it gets nothing). Furthermore, you should test whether to stop the procedure, not whether to continue:

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

But for all that, I would say the the procedure itself is not the best way to accomplish the task it does, since it is too concerned with the details of traversing a list. Instead you would use the more abstract FOR-EACH method to do the work.

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

This way, instead of a reader of the procedure getting mired in the details of CARs and CDRs, he can just understand that FOR-EACH will DISPLAY each element of NUMS.

提赋 2024-09-17 05:33:16

一些随机注释:

  • 传统上,Scheme 和 Lisp 代码使用 ;;; 作为顶级注释,;; 用于代码中的注释,使用 ;< /code> 与他们正在评论的代码位于同一行的评论。 Emacs 对此提供支持,但对这些内容的处理方式略有不同。但特别是在Scheme方面,这不再像以前那样流行,但是;;;之间的区别仍然很常见。

  • 大多数现代方案都采用了新的注释类型:有:

    • #|...|# 用于块注释 - 对于对整个文件进行注释的长文本段很有用。
    • #; 是一个注释,使实现忽略表达式,这对于调试很有用。
  • 至于要编写的实际内容,这与任何其他语言没有什么不同,除了使用更实用的方法时,您通常在如何布局代码方面有更多选择。它还使得编写组合成较大功能块的较小函数变得更加方便——这也改变了文档风格,因为许多这样的小函数将是“自文档化”的(因为它们易于阅读并且非常有用) 选择

  • 我讨厌听起来像破唱片,但我仍然认为你应该花一些时间在 HtDP 上。它在设计方案中鼓励的一件事是首先编写示例,然后编写文档,然后将其扩展为实际代码。此外,本秘籍还为您提供了具有非常标准的注释集的代码:输入/输出类型、目的声明、一些有关如何在必要时实现该函数的文档,以及可以将示例视为另一种文档(这将变成“真实”代码中的注释代码)。 (还有其他书籍在文档方面也采取了类似的立场。)

  • 最后,记录宏与记录任何其他代码没有什么不同。唯一可能有很大不同的是注释中所写的内容:您倾向于描述它扩展的代码,而不是描述某个函数正在做什么,因此注释也更多地在元上等级。宏的常见方法是在宏内部进行最少的工作——只做该级别所需的工作(例如,将表达式包装在 (lambda () ...) 中),并将实际的实现留给一个函数。这也有助于记录,因为两个相关的部分将独立地对宏如何扩展以及如何运行进行注释。

Some random notes:

  • Traditionally, Scheme and Lisp code has used ;;; for toplevel comments, ;; for comments in the code, and ; for comments on the same line as the code they're commenting on. Emacs has support for this, treating each of these a little differently. But especially on the Scheme side this is no longer as popular as it was, but the difference between ;; and ; is still common.

  • Most modern Schemes have adopted new kinds of comments: theres:

    • #|...|# for a block comment -- useful for long pieces of text that comment on the whole file.
    • #;<expr> is a comment that makes the implementation ignore the expression, which is useful for debugging.
  • As for the actual content of what to write, that's not different than any other language, except that with a more functional approach you usually have more choices on how to lay out your code. It also makes it more convenient to write smaller functions that are combined into larger pieces of functionality -- and this changes the documentation style too, since many such small functions will be "self documenting" (in that they're easy to read and very obvious in how they're working).

  • I hate to sound like a broken record, but I still think that you should spend some time with HtDP. One thing that it encourages in its design recipe is to write examples first, then the documentation, and then expand that to actual code. Furthermore, this recipe leaves you with code that has a very standard set of comments: the input/output types, a purpose statement, some documentation about how the function is implemented when necessary, and the examples can be considered as another kind of documentation (which would turn to commented code in "real" code). (There are other books that take a similar position wrt documentation.)

  • Finally, documenting macros is not different than documenting any other code. The only thing that can be very different i what's written in the comments: instead of describing what some function is doing, you tend to describe what code it expands too, so the comments are also more on the meta level. A common approach to macros is to to minimal work inside the macro -- just what's needed at that level (eg, wrap expressions in (lambda () ...)), and leave the actual implementation to a function. This helps in documenting too, since the two related pieces will have comments on how the macro expands and how it runs, independently.

孤单情人 2024-09-17 05:33:16

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

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"

I follow an approach similar to what's posted here:

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

Note: this is for Common Lisp.

Specifically:

" 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"
最冷一天 2024-09-17 05:33:16

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

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

作为开头的评论。

我对方案不是特别熟悉,所以我无法评论(:-)根据正常的方案风格是否需要额外的逐行注释来解释函数如何实现该结果的机制(但我怀疑不是)。

I think a great place to start would be to put your one-sentence description of what the function does

It can be called with any number of arguments and outputs each argument to the screen in the order that they are provided.

as a comment at the beginning.

I'm not particularly conversant in scheme, so I can't comment (:-) on whether additional line-by-line comments explaining the mechanics of how the function achieves that result would be expected according to normal scheme style (but I suspect not).

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