Comment écrire du code Clojure lisible?


13

Je suis nouveau à Clojure. Je peux comprendre le code que j'écris mais il devient trop difficile de le comprendre plus tard.
Il devient difficile de faire correspondre les parenthèses.

Quelles sont les conventions génériques à suivre concernant les conventions de dénomination et l'indentation dans diverses situations?

Par exemple, j'ai écrit un exemple d'exemple de déstructuration pour comprendre, mais il semble complètement illisible la deuxième fois.

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

En cas de déstructuration, vaut-il mieux le faire directement au niveau des paramètres ou démarrer une forme let puis continuer là?


3
Il y a une bonne réponse sur la lisibilité à Stack Overflow. Vous pouvez le vérifier. stackoverflow.com/a/1894891/1969106
yfklon

2
L'écriture de code Lisp lisible est généralement difficile. Ils ont inventé le backronym "Lost In Superfluous Parenthesis" pour une raison.
Mason Wheeler

Réponses:


23

Conventions de nommage

  • rester en minuscules pour les fonctions
  • utiliser -pour la césure (ce qui serait souligné ou cas de chameau dans d'autres langues).

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

  • Les prédicats (c'est-à-dire les fonctions renvoyant vrai ou faux) se terminent par des ? exemples:odd? even? nil? empty?

  • Fin des procédures de changement d'état !. Tu te souviens set!non? ouswap!

  • Choisissez de courtes longueurs de noms variables en fonction de leur portée. Cela signifie que si vous avez une très petite variable auxiliaire, vous pouvez souvent simplement utiliser un nom à une lettre. (map (fn [[k v]] (inc v)) {:test 4 :blub 5})choisissez des noms de variable plus longs selon les besoins, surtout s'ils sont utilisés pour de nombreuses lignes de code et que vous ne pouvez pas immédiatement deviner leur fonction. (mon avis).

    Je pense que beaucoup de programmeurs clojure ont plutôt tendance à utiliser des noms génériques et courts. Mais ce n'est bien sûr pas vraiment une observation objective. Le fait est que beaucoup de fonctions clojure sont en fait assez génériques.

Fonctions lambda

  • Vous pouvez en fait nommer des fonctions lambda. C'est pratique pour le débogage et le profilage (mon expérience ici est avec ClojureScript).

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

  • Utilisez les fonctions lambda en ligne #()comme pratique

Espace blanc

  • Il ne doit pas y avoir de lignes parens. C'est à dire fermer les parenthèses tout de suite. N'oubliez pas que les parens sont là pour l'éditeur et le compilateur, l'indentation est pour vous.

  • Les listes de paramètres de fonction vont sur une nouvelle ligne

   (contre defn
     [un B]
     (liste ab))

Cela a du sens si vous pensez aux chaînes doc. Ils se situent entre le nom de la fonction et les paramètres. La chaîne de doc suivante n'est probablement pas la plus sage;)

   (contre defn
     "Jumeler des choses"
     [un B]
     (liste ab))
  • Les données appariées peuvent être séparées par une nouvelle ligne tant que vous conservez l'appariement
  (defn f 
    [{x: x 
      y: y 
      z: z  
      [abc]: coll}] 
    (imprimer x "" y "" z "" a "" b "" c)) 

(Vous pouvez également entrer ,comme vous le souhaitez, mais cela ne vous parait pas trop).

  • Pour l'indentation, utilisez un éditeur suffisamment bon. Il y a des années, c'était emacs pour une édition nette, vim est également génial aujourd'hui. Les IDE clojure typiques devraient également fournir cette fonctionnalité. N'utilisez simplement pas un éditeur de texte aléatoire.

    Dans vim en mode commande, vous pouvez utiliser la =commande pour mettre correctement en retrait.

  • Si la commande est trop longue (imbriquée, etc.), vous pouvez insérer une nouvelle ligne après le premier argument. Maintenant, le code suivant est assez insensé mais il illustre comment vous pouvez grouper et mettre en retrait des expressions:

(+ (if-let [age (: personal-age coll)]
     (si (> 18 ans)
       âge
       0))
   (nombre (plage (- 3 b)
                 (réduire + 
                         (plage b 10)))))

Une bonne indentation signifie que vous n'avez pas à compter les parenthèses. Les crochets sont destinés à l'ordinateur (pour interpréter le code source et le mettre en retrait). L'indentation est pour votre compréhension facile.

Fonctions d'ordre supérieur foret doseqformes

Venant d'un arrière-plan Scheme, j'étais assez fier d'avoir compris maples fonctions lambda, etc. Donc, très souvent, j'écrivais quelque chose comme ça

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

C'est assez difficile à lire. Le forformulaire est bien plus agréable:

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

`map a beaucoup d'utilisations et est vraiment sympa si vous utilisez des fonctions nommées. C'est à dire

(map inc [12 30 10]

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

Utiliser des macros de thread

Utilisez les macros de thread ->et ->>ainsi que le dotocas échéant.

Le fait est que les macros de threading font apparaître le code source plus linéaire que la composition de fonction. Le morceau de code suivant est assez illisible sans la macro de thread:

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

comparer avec

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

En utilisant la macro de threading, on peut généralement éviter d'introduire des variables temporaires qui ne sont utilisées qu'une seule fois.

Autres choses

  • Utiliser des docstrings
  • garder les fonctions courtes
  • lire un autre code de clôture

Cette fonction avec déstructuration est magnifique avec indentation!
Amogh Talpallikar

+1 pour garder les fonctions courtes. Beaucoup de petites fonctions sont beaucoup plus auto-documentées
Daniel Gratzer

1
Je ne suis pas du tout d' accord pour dire que c'est une bonne idée d'utiliser des noms de variables courts, même dans les fonctions "à courte portée". Les bons noms de variables sont essentiels pour la lisibilité et ils ne coûtent rien, sauf les touches. C'est l'une des choses qui me dérange le plus dans la communauté Clojure. Il y a beaucoup de gens avec une résistance presque hostile aux noms de variables descriptives. Clojure core est jonché de noms de variables à 1 lettre pour les arguments de fonction, ce qui rend beaucoup plus difficile l'apprentissage du langage (par exemple en cours d'exécution docou sourcedans un REPL). Fin de diatribe, pour une réponse par ailleurs excellente
Nathan Wallace

@NathanWallace D'une certaine manière, je suis d'accord avec vous, mais à certains égards, je ne le fais pas. Les noms longs ont parfois tendance à rendre les fonctions trop spécifiques. Donc, vous pourriez trouver qu'une opération générale de filtrage est en fait générale, alors que lorsque l'argument était à la applesplace de xs, vous pensiez qu'il était spécifique aux pommes. Ensuite, je considérerais également que les noms d'arguments de fonction sont plus étendus que, disons, une variable de boucle for. donc si besoin, vous pouvez les avoir plus longtemps. Une dernière pensée: je vous laisse avec "Nom du code et non des valeurs" concatenative.org/wiki/view/Concatenative%20language/…
wirrbel

Je pourrais ajouter un paragraphe sur quelque chose comme les interfaces privées vs publiques. Surtout en ce qui concerne les bibliothèques. C'est un aspect de la qualité du code dont on ne parle pas assez et j'ai appris énormément à ce sujet depuis que j'ai écrit cette réponse.
wirrbel
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.