¿Cómo escribir Clojure Code legible?

12

Soy nuevo en Clojure. Puedo entender el código que escribo, pero es muy difícil entenderlo más tarde.
Se vuelve difícil hacer coincidir paréntesis.

¿Cuáles son las convenciones genéricas a seguir con respecto a las convenciones de nomenclatura y sangría en diversas situaciones?

Por ejemplo, escribí un ejemplo de desestructuración de ejemplo para comprender, pero la segunda vez parece completamente ilegible.

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

En caso de desestructuración, ¿es mejor hacerlo directamente en el nivel de parámetro o iniciar un formulario de permiso y luego continuar allí?

    
pregunta Amogh Talpallikar 07.05.2013 - 08:22

1 respuesta

22

convenciones de nombres

  • permanecer en minúsculas para funciones
  • use - para la separación de palabras (lo que sería un guión bajo o un caso de camello en otros idiomas).

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

  • Los predicados (es decir, las funciones que devuelven verdadero o falso) terminan con ?  Ejemplos: odd? even? nil? empty?

  • Los procedimientos de cambio de estado finalizan en ! . Recuerdas set! ¿verdad? o swap!

  • Elija longitudes de nombre de variable cortas dependiendo de su alcance. Eso significa que si tienes una variable auxiliar muy pequeña, a menudo puedes usar un nombre de una letra. (map (fn [[k v]] (inc v)) {:test 4 :blub 5}) elige nombres de variables más largos según sea necesario, especialmente si se usan para muchas líneas de código y no puedes adivinar su propósito de inmediato. (mi opinión).

    Siento que muchos programadores de clojure tienden a usar nombres genéricos y cortos. Pero esto, por supuesto, no es realmente una observación objetiva. El punto es que muchas de las funciones de clojure son en realidad bastante genéricas.

    • Use nombres significativos. Los procedimientos están haciendo algo, por lo que puede describirlos mejor usando verbos. Las funciones integradas de Clojure deben ponerte en el camino correcto: drop , take , assoc , etc. Luego hay un buen artículo que describe formas de elegir un nombre significativo: enlace

Funciones Lambda

  • Puedes nombrar las funciones lambda. Esto es conveniente para la depuración y la creación de perfiles (mi experiencia aquí es con ClojureScript).

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

  • Use las funciones lambda en línea #() según sea conveniente

Espacio en blanco

  • No debe haber líneas solo parens. Es decir. cierra los paréntesis de inmediato. Recuerde que hay parens para el editor y el compilador, la sangría es para usted.

  • Las listas de parámetros de función van en una nueva línea

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

Esto tiene sentido si piensas en las cadenas de documentación. Están entre el nombre de la función y los parámetros. La siguiente cadena de documentación probablemente no sea la más inteligente;)

   (defn cons
     "Pairing up things"
     [a b]
     (list a b))
  • Los datos emparejados se pueden separar con una nueva línea siempre que se mantenga el emparejamiento
  (defn f 
    [{x :x 
      y :y 
      z :z  
      [a b c] :coll}] 
    (print x " " y  " " z " " a " " b " " c)) 

(También puede ingresar , como lo desee, pero esto se siente implacable).

  • Para la sangría utilice un editor suficientemente bueno. Hace años, esto era emacs para la edición lisp, vim también es genial hoy. Los IDE típicos de clojure también deberían proporcionar esta funcionalidad. Simplemente no uses un editor de texto al azar.

    En vim en modo de comando, puedes usar el comando = para sangrar correctamente.

  • Si el comando se vuelve demasiado largo (anidado, etc.) puede insertar una nueva línea después del primer argumento. Ahora el siguiente código no tiene sentido, pero ilustra cómo puedes agrupar y sangrar expresiones:

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

Una buena sangría significa que no tienes que contar paréntesis. Los paréntesis son para la computadora (para interpretar el código fuente y para sangrarlo). La sangría es para su fácil comprensión.

Funciones de orden superior vs. for y doseq formas

A partir de un historial de Scheme, estaba bastante orgulloso de haber comprendido las funciones map y lambda, etc. Muy a menudo, escribía algo como esto

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

Esto es bastante difícil de leer. La forma for es mucho mejor:

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

'tiene muchos usos y es realmente bueno si estás usando funciones con nombre. Es decir,

(map inc [12 30 10]

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

Utilizar macros de subprocesos

Use las macros de subprocesamiento -> y ->> así como doto cuando corresponda.

El punto es que las macros de subprocesamiento hacen que el código fuente parezca más lineal que la composición de la función. El siguiente fragmento de código es bastante ilegible sin la macro de subprocesamiento:

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

comparar con

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

Al usar la macro de subprocesos, uno puede evitar la introducción de variables temporales que solo se usan una vez.

Otras cosas

  • Utilizar cadenas de documentación
  • mantener las funciones cortas
  • lee otro código de clojure
respondido por el wirrbel 07.05.2013 - 21:20

Lea otras preguntas en las etiquetas