Правильное комментирование для функционального программирования - PullRequest
12 голосов
/ 12 июля 2010

Я изучал схему и только что понял, что не знаю, как правильно комментировать код моей функциональной схемы. Я знаю как добавить комментарий, конечно - вы добавляете ; и ставите свой комментарий после него. У меня вопрос , что я должен добавить в свои комментарии, и где я должен комментировать для максимальной читабельности и понятности для других программистов, читающих мой код?

Вот фрагмент кода, который я написал. Эта функция называется 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 ]

6 голосов
/ 12 июля 2010

Общий стиль для комментариев на Лиспе

  • Четыре точки с запятой для комментариев к целому подразделу файла.
  • Три точки с запятой для введения одной процедуры.
  • Две точки с запятой для описания определения выражения / процедуры в следующей строке.
  • Одна точка с запятой для последнего комментария.

Комментарии к обзору процедуры, вероятно, должны соответствовать стилю документов 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 он запутывает заполнение абзаца.


Теперь о коде, я бы отбросил всю вещь 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))

Таким образом, вместо того, чтобы читать информацию о процедурах, попадающих в детали CAR и CDR, он может просто понять, что FOR-EACH будет отображать каждый элемент NUMS.

4 голосов
/ 12 июля 2010

Некоторые случайные заметки:

  • Традиционно код Scheme и Lisp использовал ;;; для верхнего уровня комментариев, ;; для комментариев в коде и ; для комментариев в той же строке, что и код, который они комментируют. Emacs поддерживает это, рассматривая каждый из них немного по-другому. Но особенно на стороне Схемы это уже не так популярно, как раньше, но разница между ;; и ; все еще распространена.

  • Большинство современных схем приняли новые виды комментариев: theres:

    • #|...|# для блочного комментария - полезно для длинных фрагментов текста, которые комментируют весь файл.
    • #;<expr> - это комментарий, который заставляет реализацию игнорировать выражение, которое полезно для отладки.
  • Что касается фактического содержания того, что писать, то оно ничем не отличается от любого другого языка, за исключением того, что при более функциональном подходе у вас обычно есть больше вариантов того, как выложить свой код. Это также делает более удобным написание меньших функций, которые объединяются в большие части функциональности - и это также меняет стиль документации, так как многие такие маленькие функции будут «самодокументированы» (в том смысле, что их легко читать и очень очевидно, как они работают).

  • Ненавижу звучать как неработающая пластинка, но я все еще думаю, что вам следует провести некоторое время с HtDP. Одна вещь, которую он поощряет в своем рецепте проектирования, - это сначала писать примеры, затем документацию, а затем расширять ее до реального кода. Кроме того, этот рецепт оставляет вас с кодом, который имеет очень стандартный набор комментариев: типы ввода / вывода, оператор цели, некоторую документацию о том, как функция реализуется при необходимости, и примеры могут рассматриваться как другой вид документации ( который превратился бы в комментируемый код в «реальный» код). (Существуют другие книги, занимающие аналогичную позицию в отношении документации.)

  • Наконец, документирование макросов не отличается от документирования любого другого кода. Единственное, что может сильно отличаться от того, что написано в комментариях: вместо описания того, что делает какая-то функция, вы склонны описывать, какой код она тоже расширяет , поэтому комментарии также больше на мета уровне , Обычный подход к макросам заключается в том, чтобы минимизировать работу внутри макроса - только то, что нужно на этом уровне (например, выражения переноса в (lambda () ...)), и оставить фактическую реализацию функции. Это также помогает в документировании, поскольку две связанные части будут содержать комментарии о том, как макрос расширяется и как он выполняется независимо.

2 голосов
/ 12 июля 2010

Я придерживаюсь подхода, аналогичного тому, который опубликован здесь:

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"
0 голосов
/ 12 июля 2010

Я думаю, что для начала стоит добавить описание из одной фразы того, что делает функция

Он может быть вызван с любым количеством аргументов и выводит каждый аргумент на экран в порядке их предоставления.

как комментарий в начале.

Я не особо разбираюсь в схемах, поэтому не могу прокомментировать (:-), будут ли дополнительные построчные комментарии, объясняющие механизм достижения этой функцией результата, в соответствии с обычным стилем схемы но я подозреваю, что нет).

...