5

私は 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))))))

明らかに、このコードは貧弱です。なぜなら、ここで 2 つのほぼ同一の関数呼び出しを使用することは最適ではないためです。唯一の違いは(.indexOf scale degree)vsdegreeです。

このコードの重複を取り除く Clojure/Lisp の方法は何ですか? let を含むべきだと思いますが、私は肯定的ではありません。このコード ブロックに関連するその他の一般的なポインタも歓迎します。

編集:アンドリュー・クックの提案に従ってコードをリファクタリングしました。関数は次のようになります。

(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))))
        )
    )

とても早く答えてくれたみんなに感謝します。

4

4 に答える 4

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))))))))

の結果をキャプチャするために let を使用すると、おそらくさらに良いでしょうif

于 2012-04-08T17:00:15.610 に答える
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)))))

それが役立つかどうかわからない - を使用することを除いて、一般原則はありませんlet。また、他の人は私が で値をシャドーイングする方法を好まないかもしれませんがdegree、ここでは意図を示すのに役立つと思います。

編集:他の回答と比較して、値を引き出しました。埋め込まれた評価の長いチェーンは読みにくいので、埋め込みよりもこれを好みます。ymmv。

このスタイルを複数の場所で使用している場合 (パラメーターは、前の値からデータを取得する値またはキーのいずれか)、そのプロセスを自動化するマクロを作成することを検討してください。 (つまり、上記の形式の自動生成された let で fn を生成するもの)。主な問題は、どのパラメーターがそのように扱われるかを示す方法を決定することです (また、これが使用している ide を混乱させる可能性があることも心配です)。

于 2012-04-08T17:00:34.223 に答える
4

Clojure (および他のほとんどの Lisp) ではif、他のすべての式と同じように値を返します。例えば、

(if (even? 3) 1 0)

に評価され0ます。

この知識を使用してif、次のように、コードの同一部分をステートメントの外に移動することにより、コードをリファクタリングできます。

(defn chord [scale degree num-voices]
  (take num-voices (take-nth 2
                             (cycle (invert scale 
                                            (if (keyword? degree)  
                                                (.indexOf scale degree)
                                                degree))))))

また、Lisp では、-は特別でも予約済みでもないので、変数名で使用できますし、使用する必要があります。破線のオプションの方が読みやすいと見なされるため、ornum-voicesの代わりにLisp スタイルを使用することをお勧めします。num_voicesnumVoices

于 2012-04-08T17:00:18.497 に答える
0

手順を単純化するためにできることはあまりありません。おそらく、次のようifに への呼び出し内を移動しtake num_voicesます。

(defn chord ([scale degree num_voices]
   (take num_voices
         (take-nth 2
                   (cycle (invert
                           scale
                           (if (keyword? degree) (.indexOf scale degree) degree)))))))
于 2012-04-08T17:03:20.777 に答える