2009-12-30 11 views
73

Qualcuno potrebbe fornire un collegamento ad un buon standard di codifica per Haskell? Ho trovato this e this, ma sono tutt'altro che comprensivi. Per non parlare del fatto che HaskellWiki include "gemme" come "usa le classi con cura" e "la definizione degli identificatori di simboli simbolici deve essere lasciata solo agli scrittori di librerie".Buone norme di codifica Haskell

+1

//, Non è una questione di opinione, però? –

risposta

88

Davvero una domanda difficile. Spero che le tue risposte presentino qualcosa di buono. Nel frattempo, ecco un catalogo di errori o altre cose fastidiose che ho trovato nel codice dei principianti. C'è una certa sovrapposizione con la pagina di stile Cal Tech a cui Kornel Kisielewicz punta. Alcuni dei miei consigli è altrettanto vago e inutile come le "chicche" HaskellWiki, ma spero almeno è meglio consigli :-)

  • Formato il codice in modo che si adatta in 80 colonne. (Gli utenti più esperti potrebbero preferire 87 o 88, al di là che sta spingendo esso.)

  • Non dimenticate che let attacchi e where clausole di creare un nido reciprocamente ricorsivo di definizioni, non una sequenza di di definizioni.

  • Sfruttare le clausole where, in particolare la loro capacità di visualizzare i parametri di funzione già in ambito (consigli vaghi e carini). Se sei veramente grok Haskell, il tuo codice dovrebbe avere molto più where -legamenti di let -bindings. Troppi let -bindings sono un segno di un programmatore ML o programmatore Lisp non ricostruito.

  • Evitare parentesi ridondanti. Alcuni luoghi dove parentesi ridondanti sono particolarmente offensive sono

    • Intorno la condizione in un if espressione (marche voi come un programmatore C irriducibile)

    • Circa un'applicazione funzione che è di per sé l'argomento di un operatore infisso (applicazione funzione si lega più stretto rispetto a qualsiasi operatore infisso. Questo fatto dovrebbe essere bruciato nel cervello di ogni Haskeller, più o meno allo stesso modo in cui noi dinosauri avevano di APL da destra a sinistra regola scansione bruciato in.)

  • Mettere gli spazi attorno agli operatori infissi. Metti uno spazio seguendo ogni virgola in una letterale di tupla.

  • Preferire uno spazio tra una funzione e il relativo argomento, anche se l'argomento è tra parentesi.

  • Utilizzare l'operatore $ per ridurre le parentesi. Essere consapevoli della stretta relazione tra $ e infisso .:

    f $ g $ h x == (f . g . h) x == f . g . h $ x 
    
  • non trascurare il built-in Maybe e Either tipi.

  • Mai scrivere if <expression> then True else False; la frase corretta è semplicemente <expression>.

  • Non utilizzare head o tail quando è possibile utilizzare la corrispondenza del modello.

  • Non trascurare la composizione delle funzioni con l'operatore punto infisso.

  • Utilizzare le interruzioni di riga con attenzione. Le interruzioni di riga possono aumentare la leggibilità, ma c'è un compromesso: il tuo editor può visualizzare solo 40-50 linee alla volta. Se hai bisogno di leggere e capire una grande funzione tutto in una volta, non devi abusare delle interruzioni di linea.

  • Quasi sempre preferiscono i commenti -- che vengono eseguiti fino alla fine della riga sui commenti {- ... -}. I commenti rinforzati potrebbero essere appropriati per le intestazioni di grandi dimensioni —.

  • Assegnare a ciascuna funzione di livello superiore una firma di tipo esplicita.

  • Quando possibile, allineare -- linee, = segni e perfino parentesi e virgole che si verificano nelle linee adiacenti.

  • influenzate come sono dalla GHC centrale, ho una preferenza molto mite da utilizzare per gli identificatori camelCase esportati e short_name di sottolineatura per locali where -bound o let variabili -bound.

+3

Mi piace molto questa risposta, ma puoi fornire altri esempi di codice?Non ho ancora familiarità con il gergo di Haskell, quindi "l'applicazione della funzione è più stretta di qualsiasi altro operatore infisso" e alcuni altri punti mi lasciano confuso. – CaptainCasey

+2

@CaptainCasey: ho iniziato ad aggiungere alcuni esempi, ma poi la risposta è diventata troppo lunga e difficile da leggere. È inteso come un breve insieme di suggerimenti; se deve trasformarsi in una vera guida di stile, dovrà essere fatto da qualcun altro. Ma fammi sapere i tuoi punti specifici. La tenuta vincolante significa semplicemente che '(lunghezza l) + 1' è brutto. L'applicazione di 'length' si lega automaticamente più strettamente dell'applicazione di +, quindi la cosa idiomatica da scrivere è' length l + 1'. Le parentesi sono la rovina dei programmi funzionali. –

+0

^Anche la rovina di Liskell? –

6

Suggerirei di dare un'occhiata a questo style checker.

+8

E HLint http://hackage.haskell.org/package/hlint –

6
  • mi piace cercare di organizzare le funzioni come composizioni stile libero-point come più possibile facendo le cose come:

    func = boo . boppity . bippity . snd 
        where boo = ... 
          boppity = ... 
          bippity = ... 
    
  • Mi piace usare ($) solo per evitare parenti annidati o espressioni parentesi lunghe

  • ... pensavo di averne ancora in me, oh ben

26

Alcune buone regole di pollice IMHO:

  • Consultare HLint per assicurarsi che non si dispone di bretelle ridondanti e non che il codice è inutilmente punto pieno.
  • Evitare di ricreare le funzioni di libreria esistenti. Hoogle può aiutarti a trovarli.
    • Spesso le funzioni di libreria esistenti sono più generiche di quelle che si sarebbero verificate. Ad esempio se si desidera Maybe (Maybe a) -> Maybe a, quindi lo join lo fa tra le altre cose.
  • Talvolta la denominazione e la documentazione degli argomenti sono importanti.
    • Per una funzione come replicate :: Int -> a -> [a], è piuttosto ovvio ciò che ciascuno degli argomenti fa, dai loro tipi solo.
    • Per una funzione che richiede diversi argomenti dello stesso tipo, ad esempio isPrefixOf :: (Eq a) => [a] -> [a] -> Bool, la denominazione/documentazione degli argomenti è più importante.
  • Se una funzione esiste solo per servire un'altra funzione, e non è comunque utile, e/o è difficile pensare ad un buon nome per esso, allora probabilmente dovrebbe esistere nella sua where clausola del chiamante invece che in l'ambito del modulo.
  • DRY
    • Usa modello-Haskell, quando opportuno.
    • I pacchetti di funzioni come zip3, zipWith3, zip4, zipWith4, ecc. Sono molto meh. Utilizzare invece lo stile Applicative con ZipList s. Probabilmente non hai mai veramente bisogno di funzioni come quelle.
    • Ricava automaticamente le istanze. Il pacchetto derive può aiutare a ricavare istanze per classi di tipo come Functor (esiste un solo modo corretto per rendere un tipo un'istanza di Functor).
  • codice che è più generale ha diversi vantaggi:
    • E 'più utile e riutilizzabile.
    • È meno soggetto a bug perché ci sono più vincoli.
      • Ad esempio se si desidera programmare concat :: [[a]] -> [a] e notare come può essere più generale come join :: Monad m => m (m a) -> m a. C'è meno spazio per errori quando si programma perché durante la programmazione di concat è possibile invertire gli elenchi per errore e in join ci sono pochissime cose che si possono fare.
  • Quando si utilizza lo stesso stack di trasformatori monade in molti luoghi nel codice, fare un tipo sinonimo di esso. Ciò renderà i tipi più brevi, più concisi e più facili da modificare alla rinfusa.
  • Attenzione a "IO pigro". Ad esempio, readFile non legge realmente il contenuto del file nel momento in cui il file viene letto.
  • Evita di indentare così tanto che non riesco a trovare il codice.
  • Se il proprio tipo è logicamente un'istanza di una classe di tipo, trasformarlo in un'istanza.
    • L'istanza può sostituire altre funzioni dell'interfaccia che è possibile considerare con quelle familiari.
    • Nota: se è presente più di un'istanza logica, creare newtype-wrappers per le istanze.
    • Rende coerenti le diverse istanze. Sarebbe stato molto confuso/cattivo se la lista Applicative si comportava come ZipList.
4

ho trovato buon file Markdown che copre quasi tutti gli aspetti dello stile di codice Haskell. Può essere usato come un cheat sheet. Potete trovarlo qui: link