12

Ho studiato schema e mi sono appena reso conto che non so davvero come commentare correttamente il mio codice di schema funzionale. So come aggiungere un commento naturalmente - si aggiunge uno ; e inserire il tuo commento dopo di esso. La mia domanda è cosa devo inserire nei miei commenti, e dove dovrei commentare per la massima leggibilità e comprensibilità per gli altri programmatori che leggono il mio codice?Commenti corretti per la programmazione funzionale

Ecco uno snippet di codice che ho scritto. È una funzione chiamata display-n. Può essere chiamato con qualsiasi numero di argomenti e restituisce ciascun argomento sullo schermo nell'ordine in cui vengono forniti.

(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: Migliorata la tabulazione e sostituita con '()(quote()) per evitare SO rovinare la formattazione.

Non sono sicuro di come/dove aggiungere commenti per renderlo più comprensibile. Alcuni codici di schema che ho visto hanno solo commenti in alto, il che è ottimo se si desidera utilizzare il codice, ma non utile se si desidera capirlo/modificarlo.

Inoltre, come devo commentare i macro?

risposta

6

Lo stile comune per Lisp commenti è

  • Quattro punti e virgola per il commento su un intero sottosezione di un file.
  • Tre punti e virgola per l'introduzione di una singola procedura.
  • Due punti e virgola per una descrizione della definizione di espressione/procedura nella riga seguente.
  • Un punto e virgola per un commento di fine riga.

Procedura Commenti Panoramica dovrebbero probabilmente seguire lo stile di RnRS documens, per così basta aggiungere commenti alla procedura così come sono, sarebbe simile

 
;;; 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. Non uso tre punti e virgola per l'intera descrizione della procedura, poiché svuota il paragrafo di riempimento in Emacs.


Ora, riguardo al codice, vorrei abbandonare l'intera definizione di variabile-come-una-cosa lambda.Sì, ho capito che questo è il modo "più puro" per definire una funzione, e rende la coerenza con le procedure definitive i risultati di LET e altre procedure, ma c'è una ragione per lo zucchero sintattico, ed è per rendere le cose più leggibile. Lo stesso vale per il LETREC: basta usare un DEFINE interno, che è la stessa cosa ma più leggibile.

Non è un affare enorme che il parametro del display-N-INTERNO si chiama NUMS, dal momento che il procedimento così breve e DISPLAY-N porge solo i suoi NUMS dritto ad esso comunque. "DISPLAY-N-INNER" è una specie di nome zoppo, però. Darei qualcosa con un significato più semantico, o dargli un nome semplice come "ITER" o "LOOP".

Ora sulla logica della procedura. Innanzitutto, (equal? (cdr nums) '()) è sciocco, ed è meglio come (null? (cdr nums)). In realtà, quando si opera su un intero elenco, è meglio fare in modo che il caso base verifichi se la lista stessa, e non il suo CDR, è vuota. In questo modo la procedura non verrà erroneamente se non si passa nessun argomento (a meno che non si voglia farlo, ma penso che abbia più senso per DISPLAY-N a do nulla se non ottiene nulla). Inoltre, è necessario verificare se fermare la procedura, non è se continuare:

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

Ma per tutto questo, direi che la procedura stessa non è il modo migliore per realizzare il compito che fa, dal momento che è troppo interessato ai dettagli di attraversare una lista. Invece dovresti usare il metodo FOR-EACH più astratto per fare il lavoro.

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

questo modo, invece di un lettore della procedura di ottenere impantanato nei dettagli di automobili e CDR, si può solo capire che la for-each mostrerà ogni elemento di NUMS.

+0

+1, tutto ciò è un buon consiglio (specialmente la parte sullo zucchero sintattico). Inoltre, tbh in realtà non sapevo di 'null?' - quindi è utile. Per quanto mi riguarda, mi rendo conto che è il modo migliore per affrontare effettivamente questo particolare problema, ma il mio frammento di codice sarebbe stato troppo banale :) – Cam

+0

Come un'altra forma intermedia, perché usare la procedura interna? È possibile rendere il ricorsivo esterno senza perdita di incapsulamento. – Svante

+0

@Svante: È perché il 'nums 'esterno è una lista composta da tutti gli argomenti forniti alla funzione. Chiamando la procedura esterna in modo ricorsivo si fornisce solo un parametro, gli argomenti sotto forma di elenco. Il problema è che 'display-n' si aspetta in realtà più argomenti - non un argomento che è una lista, quindi non funzionerebbe. Detto questo, il tuo suggerimento sarebbe possibile usando 'apply' - eccetto che non sono sicuro di quanto sia efficace' apply', così che comunque potrebbe non essere una buona soluzione. – Cam

0

Credo che un ottimo punto di partenza sarebbe quello di mettere la vostra descrizione di una frase ciò che la funzione fa

Può essere chiamato con un numero qualsiasi di argomenti e uscite ogni argomento alla schermata nell'ordine che sono forniti.

come commento all'inizio.

Io non sono particolarmente esperto nello schema, quindi non posso commentare (:-) sul fatto che ulteriori commenti riga per riga che spiegano la meccanica di come la funzione ottiene quel risultato sarebbero previsti secondo il normale stile di schema (ma non sospetto).

2

seguo un approccio simile a quello che è scritto qui:

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

Nota: questo è per Common Lisp.

In particolare:

" 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" 
4

Alcune note casuali:

  • Tradizionalmente, Scheme e il codice Lisp ha utilizzato ;;; per i commenti toplevel, ;; per i commenti nel codice, e ; per i commenti sulla stessa linea del codice su cui stanno commentando. Emacs ha il supporto per questo, trattando ciascuno di questi un po 'diversamente. Ma soprattutto sul lato Scheme questo non è più così popolare, ma la differenza tra ;; e ; è ancora comune.

  • maggior parte dei regimi moderni hanno adottato nuovi tipi di commenti: Theres:

    • #|...|# per un blocco di commento - utile per lunghi pezzi di testo che commentano l'intero file.
    • #;<expr> è un commento che fa ignorare l'implementazione, che è utile per il debug.
  • Per quanto riguarda il contenuto effettivo di cosa scrivere, non è diverso da qualsiasi altra lingua, tranne che con un approccio più funzionale di solito si hanno più scelte su come disporre il codice. Rende anche più conveniente scrivere funzioni più piccole che sono combinate in più grandi funzionalità - e questo cambia anche lo stile della documentazione, dal momento che molte di queste piccole funzioni saranno "autodocumentanti" (in quanto sono facili da leggere e molto ovvio nel modo in cui stanno lavorando).

  • Detesto sembrare un record interrotto, ma continuo a pensare che dovresti passare un po 'di tempo con HtDP. Una cosa che incoraggia nella sua ricetta di progettazione è scrivere prima degli esempi, poi la documentazione, e poi espanderla al codice attuale. Inoltre, questa ricetta ti lascia con un codice che ha una serie di commenti molto standard: i tipi di input/output, una dichiarazione di scopo, una documentazione su come la funzione viene implementata quando necessario, e gli esempi possono essere considerati come un altro tipo di documentazione (che si trasformerebbe in codice commentato in codice "reale"). (Esistono altri libri che occupano una posizione simile rispetto alla documentazione.)

  • Infine, la documentazione di macro non è diversa dalla documentazione di qualsiasi altro codice. L'unica cosa che può essere molto diversa è ciò che è scritto nei commenti: invece di descrivere cosa sta facendo qualche funzione, si tende a descrivere quale codice lo espande anche, quindi i commenti sono anche più sul meta livello. Un approccio comune ai macro è quello di minimizzare il lavoro all'interno della macro: solo ciò che è necessario a quel livello (ad esempio, avvolgere le espressioni in (lambda() ...)) e lasciare l'implementazione effettiva a una funzione. Questo aiuta anche a documentare, dal momento che i due pezzi correlati avranno commenti su come la macro si espande e su come funziona, indipendentemente.

+0

+1, Grazie - utile come al solito. In particolare, apprezzo il secondo e l'ultimo punto. – Cam