I'm very new to clojure, and I haven't done a ton of lisp previously. I have a function that contains the following:
(defn chord
([scale degree num_voices]
(if
(keyword? degree)
(take num_voices (take-nth 2 (cycle (invert scale (.indexOf scale degree)))))
(take num_voices (take-nth 2 (cycle (invert scale degree))))))
Obviously, this code is poor because having two almost-identical function calls here is suboptimal, where the only difference is (.indexOf scale degree)
vs degree
.
What's the Clojure/Lisp Way of removing this code duplication? I feel like it should involve a let, but I'm not positive. Any other general pointers related to this code block are also appreciated.
Edit: I have re-factored the code according to andrew cooke's suggestion, the function now reads:
(defn chord
([scale degree num_voices]
(let [degree (if (keyword? degree) (.indexOf scale degree) degree)]
(take num_voices (take-nth 2 (cycle (invert scale degree))))
)
)
Thanks to everyone who answered so quickly.
i would write:
(defn chord [scale degree num_voices]
(let [degree (if (keyword? degree) (.indexOf scale degree) degree)]
(take num_voices (take-nth 2 (cycle (invert scale degree)))))
not sure it helps - no general principle, except using let
. also, maybe others wouldn't like the way i shadow values with degree
, but here i think it helps show the intent.
edit: compared to other answers, i have pulled out the value. i prefer this to embedding because i find a long chain of embedded evaluations harder to read. ymmv.
ps thinking some more [this some days later] if you are using this style in multiple places (where a parameter can be either a value or a key that pulls data from a preceding value) then i might consider writing a macro to automate that process (ie something that generates a fn with auto-generated let of the form above). the main problem is deciding how to indicate which paraneters are treated in that way (and also, i would worry about how this could confuse any ide you are using).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With