Я изучал схему, и я просто понял, что действительно не знаю, как правильно прокомментировать мой функциональный код схемы. Я знаю, как добавить комментарий, конечно - Вы добавляете a ;
и помещенный Ваш комментарий после него. Мой вопрос - то, что я должен вставить свои комментарии, и где я должен прокомментировать для максимальной удобочитаемости и понятности для других программистов, читающих мой код?
Вот фрагмент кода, который я записал. Это - вызванная функция 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 ())
избегать НАСТОЛЬКО портящий форматирование.
Я просто не уверен, как/где добавить комментарии для создания этого более понятным. Некоторая схема кодирует, я видел, просто имеет комментарии наверху, который является большим, если Вы хотите использовать код, но не полезные, если Вы хотите понять/изменить это.
Также - как я должен прокомментировать макросы?
Обычный стиль комментариев в 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. Я не использую три точки с запятой для всего описания процедуры, поскольку это портит fill-paragraph в 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.
Некоторые случайные примечания:
Традиционно в коде Scheme и Lisp использовались ;;;
для комментариев верхнего уровня, ;;
для комментариев в коде и ;
для комментариев к той же строке, что и код, который они комментируют. Emacs поддерживает это, рассматривая каждый из них немного по-своему. Но особенно на стороне схемы это уже не так популярно, как было, но разница между ;;
и ;
по-прежнему распространена.
В большинстве современных схем используются новые виды комментариев: theres:
# | ... | #
для блочного комментария - полезно для длинных фрагментов текста, которые комментируют весь файл. #;
- это комментарий, который заставляет реализацию игнорировать выражение, что полезно для отладки. Что касается фактического содержания того, что писать, оно не отличается от любого другого языка, за исключением того, что при более функциональном подходе у вас обычно есть больше вариантов того, как разложить свой код. Это также делает более удобным написание более мелких функций, которые объединяются в более крупные функциональные возможности - и это также меняет стиль документации, поскольку многие такие небольшие функции будут «самодокументироваться» (в том смысле, что они легко читаются и очень очевидно, как они работают).
Мне неприятно звучать как зажившая пластинка, но я все же считаю, что вам стоит потратить некоторое время на HtDP. Одна вещь, которую он поощряет в своем рецепте дизайна, - это сначала писать примеры, затем документацию, а затем расширять ее до реального кода.Кроме того, этот рецепт оставляет вам код с очень стандартным набором комментариев: типы ввода / вывода, формулировку цели, некоторую документацию о том, как реализована функция, когда это необходимо, и примеры можно рассматривать как другой вид документации ( который превратился бы в закомментированный код в «реальном» коде). (Есть и другие книги, которые занимают аналогичную позицию по отношению к документации.)
Наконец, документирование макросов ничем не отличается от документирования любого другого кода. Единственное, что может сильно отличаться от того, что написано в комментариях: вместо описания того, что делает какая-то функция, вы склонны описывать, какой код она также расширяет , поэтому комментарии также больше относятся к мета-уровню . Общий подход к макросам заключается в минимальной работе внутри макроса - именно то, что необходимо на этом уровне (например, обернуть выражения в (lambda () ...)
), а фактическую реализацию оставить на функция. Это также помогает в документировании, поскольку в двух связанных частях будут комментарии о том, как макрос расширяется и как он выполняется независимо.
Я использую подход, похожий на тот, что выложен здесь:
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"
Я думаю, отличным местом для начала было бы поместить ваше односложное описание того, что делает функция
Она может быть вызвана с любым количеством аргументов и выводит каждый аргумент на экран в том порядке, в котором они предоставлены.
в качестве комментария в начале.
Я не особенно разбираюсь в схеме, поэтому не могу прокомментировать (:-)), ожидаются ли дополнительные построчные комментарии, объясняющие механику того, как функция достигает этого результата, в соответствии с обычным стилем схемы (но я подозреваю, что нет).