clojure:在"if"中删除重复的惯用方法?

Pau*_*ald 5 lisp refactoring clojure

我对clojure很新,而且我之前没有做过大量的lisp.我有一个包含以下内容的函数:

(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))))))
Run Code Online (Sandbox Code Playgroud)

很显然,这个代码是差,因为有两个几乎相同的函数调用这里是最理想的,这里唯一的区别是(.indexOf scale degree)VS degree.

什么是Clojure/Lisp删除此代码重复的方法?我觉得它应该涉及让,但我不是积极的.还可以理解与该代码块相关的任何其他通用指针.

编辑:我根据andrew cooke的建议重新考虑了代码,该函数现在读取:

(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))))
        )
    )
Run Code Online (Sandbox Code Playgroud)

感谢所有回答如此之快的人.

Mar*_*cin 6

if 返回一个表达式,因此反转函数的结构:

(defn chord 
    ([scale degree num_voices]
    (take num_voices (take-nth 2 (cycle (invert scale (if (keyword? degree)
                                                              (.indexOf scale degree)
                                                           (invert scale degree))))))))
Run Code Online (Sandbox Code Playgroud)

如果你使用let来捕获结果,那可能会更好if.


and*_*oke 6

我会写:

(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)))))
Run Code Online (Sandbox Code Playgroud)

不确定它有帮助 - 没有一般原则,除了使用let.也许,也许其他人不喜欢我影子价值观的方式degree,但在这里我认为它有助于显示意图.

编辑:与其他答案相比,我已经拿出了价值.我更喜欢这种嵌入,因为我发现很长一段时间的嵌入式评估难以阅读.因人而异.

PS思考些[这一些天后]如果您正在使用多个地方这种风格(其中一个参数可以是一个值或从之前的值中提取数据的关键),那么我可能会考虑写一个宏来自动执行该过程(即生成带有自动生成的上述形式的fn的东西).主要的问题是决定如何以这种方式指出哪些参与者被处理(而且,我会担心这会如何混淆你正在使用的任何一个ide).