Come scrivere codice Clojure leggibile?

12

Sono nuovo di Clojure. Posso capire il codice che scrivo ma diventa troppo difficile capirlo in seguito.
Diventa difficile abbinare le parentesi.

Quali sono le convenzioni generiche da seguire in merito alle convenzioni di denominazione e all'indentazione in varie situazioni?

Ad esempio, ho scritto un esempio di de-strutturazione di esempio per capire ma sembra completamente illeggibile la seconda volta.

(defn f [{x :x y :y z :z [a b c] :coll}] (print x " " y  " " z " " a " " b " " c)) 

In caso di destrutturazione, è meglio farlo direttamente a livello di parametro o avviare un modulo let e poi continuare lì?

    
posta Amogh Talpallikar 07.05.2013 - 08:22
fonte

1 risposta

22

Convenzioni di denominazione

  • resta in minuscolo per le funzioni
  • usa - per la sillabazione (quale sarebbe underscore o caso cammello in altre lingue).

    (defn add-one [i] (inc i))

  • I predicati (ovvero le funzioni che restituiscono true o false) terminano con ?  Esempi: odd? even? nil? empty?

  • Le procedure di modifica dello stato terminano in ! . Ti ricordi set! giusto? o swap!

  • Scegli lunghezze dei nomi delle variabili brevi in base alla loro portata. Ciò significa che se si dispone di una variabile ausiliaria molto piccola è spesso possibile utilizzare solo un nome di una sola lettera. (map (fn [[k v]] (inc v)) {:test 4 :blub 5}) sceglie nomi di variabile più lunghi secondo necessità, specialmente se sono usati per molte linee di codice e non è possibile indovinarne immediatamente lo scopo. (la mia opinione).

    Ritengo che molti programmatori di clojure tendano piuttosto a usare nomi generici e abbreviati. Ma ovviamente non è un'osservazione oggettiva. Il punto è che molte funzioni del clojure sono in realtà piuttosto generiche.

    • Usa nomi significativi. Le procedure stanno facendo qualcosa, quindi puoi descriverli al meglio usando i verbi. Le funzioni built-in di Clojure dovrebbero metterti sulla giusta traccia: drop , take , assoc , ecc. Poi c'è un bell'articolo che descrive i modi per scegliere un nome significativo: link

Funzioni Lambda

  • In realtà puoi nominare le funzioni lambda. Questo è conveniente per il debugging e la profilazione (la mia esperienza qui è con ClojureScript).

    (fn square-em [[k v]] {k (* v v)})

  • Usa le funzioni lambda in linea #() come conveniente

Whitespace

  • Non ci dovrebbero essere linee parens-only. Cioè chiudi subito le parentesi. Ricorda che ci sono i parens per l'editor e il compilatore, il rientro è per te.

  • Gli elenchi dei parametri delle funzioni vanno su una nuova riga

   (defn cons
     [a b]
     (list a b))

Questo ha senso se pensi alle stringhe doc. Sono tra il nome della funzione e i parametri. La seguente stringa doc probabilmente non è la più saggia;)

   (defn cons
     "Pairing up things"
     [a b]
     (list a b))
  • I dati accoppiati possono essere separati da una nuova riga se si mantiene l'associazione
  (defn f 
    [{x :x 
      y :y 
      z :z  
      [a b c] :coll}] 
    (print x " " y  " " z " " a " " b " " c)) 

(Puoi anche inserire , come preferisci, ma questo non sembra lelo).

  • Per indentazione usa un editor sufficientemente buono. Anni fa questo è stato emac per un editor nitido, anche oggi è fantastico. Anche gli IDE dei clojure tipici dovrebbero fornire questa funzionalità. Basta non usare un editor di testo casuale.

    In vim in modalità comando puoi usare il comando = per indentare correttamente.

  • Se il comando diventa troppo lungo (annidato, ecc.) è possibile inserire una nuova riga dopo il primo argomento. Ora il seguente codice è piuttosto insensato ma illustra come puoi raggruppare e indentare espressioni:

(+ (if-let [age (:personal-age coll)]
     (if (> age 18)
       age
       0))
   (count (range (- 3 b)
                 (reduce + 
                         (range b 10)))))

Una buona indentazione significa che non devi contare le parentesi. Le parentesi sono per il computer (per interpretare il codice sorgente e per indentarlo). La rientranza è per tua comprensione.

Funzioni di ordine superiore rispetto a for e doseq moduli

Provenendo da uno sfondo di Scheme ero piuttosto orgoglioso di aver capito map e funzioni lambda, ecc. Quindi abbastanza spesso, scriverei qualcosa di simile

(map (fn [[k x]] (+ x (k data))) {:a 10 :b 20 :c 30})

Questo è piuttosto difficile da leggere. La forma for è molto più bella:

(for [[k x] {:a 10 :b 20 :c30}]
  (+ x (k data)))
La

'mappa ha molti usi ed è davvero bella se usi le funzioni con nome. Cioè.

(map inc [12 30 10]

(map count [[10 20 23] [1 2 3 4 5] (range 5)])

Utilizza macro di threading

Utilizza le macro di threading -> e ->> e doto quando applicabile.

Il punto è che le macro di threading rendono il codice sorgente più lineare della composizione della funzione. La seguente parte di codice è piuttosto illeggibile senza la macro di threading:

   (f (g (h 3) 10) [10 3 2 3])

confronta con

   (-> 
     (h 3)
     (g 10)
     (f [10 3 2 3]))

Usando la macro di threading, si può in genere evitare di introdurre variabili temporanee che vengono utilizzate solo una volta.

Altre cose

  • Utilizza le docstring
  • mantieni le funzioni in breve
  • leggi altro codice clojure
risposta data 07.05.2013 - 21:20
fonte

Leggi altre domande sui tag