Se si dispone di una catena lunga espressione, utilizzare let
. Lunghe espressioni in fuga o espressioni profondamente annidate non sono particolarmente leggibili in nessuna lingua. Questo è un male:
(do-something (map :id (filter #(> (:age %) 19) (fetch-data :people))))
Questo è marginalmente migliore:
(do-something (map :id
(filter #(> (:age %) 19)
(fetch-data :people))))
Ma questo è anche un male:
fetch_data(:people).select{|x| x.age > 19}.map{|x| x.id}.do_something
Se stai leggendo questo, che cosa abbiamo bisogno di sapere? Stiamo chiamando do_something
su alcuni attributi di alcuni sottoinsiemi di people
. Questo codice è difficile da leggere perché c'è così tanta distanza tra il primo e l'ultimo, che dimentichiamo quello che stiamo guardando nel momento in cui viaggiamo tra di loro.
Nel caso di Ruby, do_something
(o qualsiasi altra cosa produca il nostro risultato finale) è perso alla fine della riga, quindi è difficile dire cosa stiamo facendo al nostro people
. Nel caso di Clojure, è ovvio che lo do-something
è quello che stiamo facendo, ma è difficile dire a cosa stiamo andando senza leggere l'intera cosa all'interno.
Qualsiasi codice più complesso di questo semplice esempio diventerà piuttosto doloroso. Se tutto il tuo codice è simile a questo, il tuo collo si stancherà a scrutare avanti e indietro su tutte queste linee di spaghetti.
Preferirei qualcosa di simile:
(let [people (fetch-data :people)
adults (filter #(> (:age %) 19) people)
ids (map :id adults)]
(do-something ids))
Ora è ovvio: comincio con people
, ho goof intorno, e poi ho do-something
a loro.
E si potrebbe ottenere via con questo:
fetch_data(:people).select{|x|
x.age > 19
}.map{|x|
x.id
}.do_something
Ma probabilmente sarei piuttosto fare questo, per lo meno:
adults = fetch_data(:people).select{|x| x.age > 19}
do_something(adults.map{|x| x.id})
Non è anche inaudito di utilizzare let
anche quando le tue espressioni intermedie non hanno un buon nome. (Questo stile è talvolta usato nel codice sorgente del proprio Clojure, ad esempio, il codice sorgente per 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))
questo può essere di grande aiuto nel debugging, in quanto è possibile controllare le cose in qualsiasi punto facendo:
(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))
Penso che sia solo un idioma perché è quello a cui sei abituato. La notazione del prefisso è molto più coerente di infisso e quindi può essere più facile da leggere una volta che ci si abitua. –
Mike, considera che è necessario scrivere espressione '(filtro # (expr1) (mappa # (expr2) expr3))'. Cominceresti a scrivere da expr3 interno o da filtro? – Alexey
Di solito parto dall'esterno e mi faccio strada dentro. Quindi penso a quello che voglio e semplicemente cammino indietro da quello. –