Si usted tiene una cadena larga de expresión, utilice let
. Las expresiones de larga huida o las expresiones profundamente anidadas no son especialmente legibles en ningún idioma. Esto es malo:
(do-something (map :id (filter #(> (:age %) 19) (fetch-data :people))))
Esto es marginalmente mejor:
(do-something (map :id
(filter #(> (:age %) 19)
(fetch-data :people))))
Pero esto también es malo:
fetch_data(:people).select{|x| x.age > 19}.map{|x| x.id}.do_something
Si estamos leyendo esto, ¿qué necesitamos saber? Estamos llamando al do_something
sobre algunos atributos de algún subconjunto de people
. Este código es difícil de leer porque hay tanta distancia entre el primero y el último, que nos olvidamos de lo que estamos mirando en el momento en que viajamos entre ellos.
En el caso de Ruby, do_something
(o lo que sea que está produciendo nuestro resultado final) se pierde camino al final de la línea, por lo que es difícil decir lo que estamos haciendo a nuestro people
. En el caso de Clojure, es inmediatamente obvio que do-something
es lo que estamos haciendo, pero es difícil decir a qué lo estamos haciendo sin leer todo el asunto desde adentro.
Cualquier código más complejo que este simple ejemplo va a ser muy doloroso. Si todo tu código se ve así, tu cuello se cansará al explorar todas estas líneas de espagueti.
prefiero algo como esto:
(let [people (fetch-data :people)
adults (filter #(> (:age %) 19) people)
ids (map :id adults)]
(do-something ids))
Ahora es obvio: Comienzo con people
, que joder, y luego me do-something
a ellos.
Y puede salirse con la suya:
fetch_data(:people).select{|x|
x.age > 19
}.map{|x|
x.id
}.do_something
Pero probablemente preferiría hacer esto, por lo menos:
adults = fetch_data(:people).select{|x| x.age > 19}
do_something(adults.map{|x| x.id})
Tampoco es raro utilizar let
incluso cuando sus expresiones intermedias no tienen buenos nombres. (Este estilo se utiliza de vez en cuando en el propio código fuente de Clojure, por ejemplo, el código fuente de defmacro
)
(let [x (complex-expr-1 x)
x (complex-expr-2 x)
x (complex-expr-3 x)
...
x (complex-expr-n x)]
(do-something x))
Esto puede ser de gran ayuda en la depuración, porque se puede inspeccionar las cosas en cualquier momento haciendo:
(let [x (complex-expr-1 x)
x (complex-expr-2 x)
_ (prn x)
x (complex-expr-3 x)
...
x (complex-expr-n x)]
(do-something x))
Creo que es solo idiomático porque es a lo que estás acostumbrado. La notación de prefijo es mucho más consistente que infijo, por lo que puede ser más fácil de leer una vez que te acostumbras. –
Mike, considere que necesita escribir la expresión '(filter # (expr1) (map # (expr2) expr3))'. ¿Comenzarías a escribir desde expr3 interno o desde filtro? – Alexey
Normalmente empiezo desde afuera y me abro camino. Así que pienso en lo que quiero y simplemente retrocedo. –