web-dev-qa-db-ja.com

読みやすいClojureコードを書くには?

Clojureは初めてです。作成したコードは理解できますが、後で理解するのが難しくなります。
括弧のマッチングが困難になります。

さまざまな状況での命名規則とインデントに関して従うべき一般的な規則は何ですか?

たとえば、私は理解するためにサンプルの解体例を書きましたが、2回目は完全に判読できません。

(defn f [{x :x y :y z :z [a b c] :coll}] (print x " " y  " " z " " a " " b " " c)) 

構造化解除の場合は、パラメーターレベルで直接実行するか、letフォームを開始してそこで続行する方が良いですか。

13

命名規則

  • 関数の場合は小文字のまま
  • ハイフネーションには_-_を使用します(他の言語ではアンダースコアまたはキャメルケースになります)。

    _(defn add-one [i] (inc i))_

  • 述語(つまり、trueまたはfalseを返す関数)は_?_で終わります例:_odd?_ _even?_ _nil?_ _empty?_

  • 状態変更手順は_!_で終わります。あなたは_set!_を覚えていますか?または_swap!_

  • リーチに応じて、変数名の長さを短くしてください。つまり、非常に小さな補助変数がある場合、多くの場合、1文字の名前を使用できます。 _(map (fn [[k v]] (inc v)) {:test 4 :blub 5})_必要に応じてより長い変数名を選択します。特に、それらが多くのコード行に使用されており、それらの目的をすぐに推測できない場合は特にそうです。 (私の意見)。

    多くのclojureプログラマーは、一般的で短い名前を使用する傾向があると感じています。しかし、これはもちろん実際には客観的な観察ではありません。ポイントは、多くのclojure関数が実際には非常に汎用的であるということです。

    • 意味のある名前を使用します。手順は何かをしているので、動詞を使用してそれらを最もよく説明できます。 Clojureの組み込み関数を使用すると、正しい軌道に乗ることができます:droptakeassocなど。意味のある名前を選択する方法を説明した素晴らしい記事があります。 http://ecmendenhall.github.io/blog/blog/2013/09/02/clean-clojure-meaningful-names/

ラムダ関数

  • 実際にラムダ関数に名前を付けることができます。これはデバッグとプロファイリングに便利です(ここでの経験はClojureScriptでの経験です)。

    _(fn square-em [[k v]] {k (* v v)})_

  • インラインラムダ関数#()を便利に使用する

空白

  • 括弧のみの行があってはなりません。つまりすぐに括弧を閉じてください。括弧はエディターとコンパイラーのためにあり、インデントはあなたのためです。

  • 関数パラメーターリストが改行されます

(defn cons 
 [a b] 
(list a b))

これは、doc文字列について考える場合に意味があります。それらは、関数名とパラメーターの間にあります。次のドキュメント文字列はおそらく最も賢明ではありません;)

(defn cons 
 "Pairing up things" 
 [a b] 
(list a b))
  • ペアリングされたデータは、ペアリングを維持している限り、新しい行で区切ることができます
(defn f 
 [{x:x 
 y:y 
 z:z 
 [abc]:coll}] 
(print x "" y "" z "" a "" b "" c))

(また、好きなように_,_を入力することもできますが、これは不自然に感じられます)。

  • インデントには十分に優れたエディタを使用してください。数年前、これはLISP編集用のemacsでしたが、vimも今日は素晴らしいです。一般的なclojure IDEもこの機能を提供する必要があります。ランダムなテキストエディタを使用しないでください。

    コマンドモードのvimでは、_=_コマンドを使用して適切にインデントできます。

  • コマンドが長すぎる(ネストされているなど)場合は、最初の引数の後に改行を挿入できます。次のコードは無意味ですが、式をグループ化してインデントする方法を示しています。

(+(if-let [age(:personal-age coll)] 
(if(> age 18)
 age 
 0))
(count(range(-3 b)
(reduce + 
(range b 10)))))

適切なインデントは、角かっこを数える必要がないことを意味します。括弧はコンピューター用です(ソースコードを解釈してインデントするため)。インデントは、理解を容易にするためのものです。

高次関数とforおよびdoseq形式

Schemeの背景から来て、mapやラムダ関数などを理解できたことをかなり誇りに思っていました。

_(map (fn [[k x]] (+ x (k data))) {:a 10 :b 20 :c 30})_

これは非常に読みにくいです。 forフォームの方がずっといいです:

_(for [[k x] {:a 10 :b 20 :c30}]
  (+ x (k data)))
_

`mapには多くの用途があり、名前付き関数を使用している場合は本当に素晴らしいです。つまり.

_(map inc [12 30 10]

(map count [[10 20 23] [1 2 3 4 5] (range 5)])
_

スレッド化マクロを使用する

スレッドマクロ_->_および_->>_を使用します(該当する場合はdotoも同様)。

重要なのは、スレッド化マクロにより、ソースコードが関数構成よりも線形に見えるようになることです。次のコードは、スレッドマクロがなければかなり読みにくくなっています。

_   (f (g (h 3) 10) [10 3 2 3])
_

と比べて

_   (-> 
     (h 3)
     (g 10)
     (f [10 3 2 3]))
_

スレッド化マクロを使用することにより、通常、1回だけ使用される一時変数の導入を回避できます。

他のもの

  • ドキュメント文字列を使用する
  • 関数を短くしてください
  • 他のClojureコードを読み取る
23
wirrbel